bcrypt模块用于对用户密码进行加密。
bcrypt 算法相对来说是运算比较慢的算法,在密码学界有句常话:越慢的算法越安全。算法越慢,黑客破解成本越高。
通过salt 和 cost
这两个值来减缓加密过程。bcrypt是单向的,而且经过salt 和 cost
的处理,使其受rainbow攻击破解的概率大大降低,同时破解的难度也提升不少,相对于MD5等加密方式更加安全,而且使用也比较简单。
bcrypt算法将salt随机并混入最终加密后的密码,验证时也无需单独提供之前的salt,从而无需单独处理salt问题。
其实,说这么多还是得学会怎么用!
npm i bcrypt --save
我们使用bcrypt模块是为了给用户密码等隐秘信息加密,这样就能防止密码泄露等问题。
密码加密实例代码:
//1、引入模块
let bcrypt= require("bcrypt");
//2、 产生salt
let salt = bcrypt.genSaltSync(11); // 11 是迭代次数
//3、加密
// 格式:bcrypt.hashSync(用户注册时输入的密码,salt);
let pass = bcrypt.hashSync("123456",salt);
console.log("pass",pass);//pass就是加密后的结果,把这个可以存储到数据库中
//加密后的密码格式如下:
// $2b$10$1MtFAztjfpDTm8z.PjQTwOo6k4FrRiXwbZKq0oAKWqWI94mhzJfTG
这时,我们存入数据库的密码就变成加密过后的内容了,那在登录时怎么对比用户输入的密码是否正确呢?
接着往下看:
// 验证密码是否正确
//1、引入模块
let bcrypt= require("bcrypt");
//格式:bcrypt.compareSync(用户登录时输入的密码,数据库中拿到的密码);
let isMatch = bcrypt.compareSync("123456","$2b$11$jMC6xi32MVFDApY.valjJ.f7W5gGXQoLj3VZlrPQ8Fik.pVQ/szTK");
//true:表示密码一致;false:密码不一致
console.log(isMatch);
这样就ok了!
HTTP 是一种无状态的协议,也就是它并不知道是谁访问(每次的访问和以前哪次的访问来自同一个客户端)。客户端用户名密码通过了身份验证,但是下次这个客户端再发送请求时候,还得再验证。
有问题肯定就有解决方案:(以下2种)
1)、当用户打开浏览器,首次访问某个网站(服务器),服务器会产生一个唯一的编号(sessionId),在响应时,把该编号发给客户端,客户端把该编号存储在cookie里。
2)、当用户二次访问(如:点击超链)服务器,那么,请求时,会携带保存在cookie里的编号,服务器端拿到该编号后,会跟session中的编号进行对比,就可以判断本次访问和哪次访问是同一个客户端。
1、客户端发送用户名和密码,请求登录
2、服务端收到请求,验证用户名与密码
3、验证成功后,服务端种一个cookie或发一个字符到客户端,同时服务器保留一份session
4、客户端收到 响应 以后可以把收到的字符存到cookie
5、客户端每次向服务端请求资源的cookie会自动携带
6、服务端收到请求,然后去验证cookie和session,如果验证成功,就向客户端返回请求的库数据
Session存储位置: 服务器内存,磁盘,或者数据库里
Session存储内容: id,存储时间,用户名等
客户端携带 : cookie自动带
1、安装
npm i express-session -S
2、引入session模块:
var session = require('express-session');
3、创建session中间件:
app.use(session(options));
实例代码:
app.use(session({
secret: 'recommend 128 bytes random string',
cookie: { maxAge: 20 * 60 * 1000 },//session的过期时间(没有错,cookie和session息息相关,所以,是用cookie.maxAge来设置session的过期时间)
resave: true,
saveUninitialized: true
})
);
4、保存变量:
req.session.变量名= 值;
5、获取变量:
req.session.变量名
用的较多。
在服务端不需要存储用户的登录记录,全部发给客户端由客户端自己存(cookie,localStorage
)
1、客户端使用用户名跟密码请求登录
2、服务端收到请求,去验证用户名与密码
3、验证成功后,服务端会签发一个 Token(加了密的字符串),再把这个 Token 发送给客户端
4、客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
5、客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
6、服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据
npm i jsonwebtoken -S
let jwt = require('jsonwebtoken')
let token = jwt.sign(payload, secretOrPrivateKey, [options, callback])
jwt.verify(token, secretOrPublicKey, [options, callback])
token: 制作后的token
secretOrPublicKey] 解密规则,字符串,或者公钥
callback: 回调 err 错误信息 decode 成功后的信息
options] expiresIn 过期时间
session | token | |
---|---|---|
服务端保存用户信息 | √ | × |
避免CSRF攻击 | × | √ |
多服务器粘性问题 | 存在 | 不存在 |
解释一下多服务器粘性问题:
当在应用中进行 session的读,写或者删除操作时,会有一个文件操作发生在操作系统的temp文件夹下,至少在第一次时。假设有多台服务器并且 session在第一台服务上创建。
当你再次发送请求并且这个请求落在另一台服务器上,session
信息并不存在并且会获得一个“未认证”的响应。这时候,就需要把在第一台服务器上保存的session给其它服务器上也保存。然而,在基于token 的认证中,这个问题很自然就被解决了。没有粘性 session 的问题,因为在每个发送到服务器的请求中这个请求的 token都会被拦截。
cookie/localstorage
服务器给浏览器种cookie: cookie-parser
Cookie的创建(express会将其填入Response Header中的Set-Cookie):
格式:
1、添加cookie
res.cookie(name, value [, options]);
//参数:
name: cookie名
value: 类型为String和Object。
Option: 类型为对象,可使用的属性如下:
domain:cookie在什么域名下有效,类型为String,。默认为网站域名
expires: cookie过期时间,类型为Date。如果没有设置或者设置为0,那么该cookie只在这个session有效
maxAge: 实现expires的功能,设置cookie过期的时间,类型为String,指明从现在开始,多少毫秒以后,cookie到期。
path: cookie在什么路径下有效,默认为'/',类型为String
secure:只能被HTTPS使用,类型Boolean,默认为false
2、删除cookie
res.clearCookie(name [, options]);
3、获取cookie
req.cookies.键名 //cookie是在客户端保存,每次请求时会携带,所以,用req对象获取cookie
示例:
//设置键为name,值为:baobao,可访问的域名为:.example.com,可访问的路径:/admin',只可以用https访问
res.cookie('name', 'baobao', {
domain: '.example.com',
maxAge:10000*1000,
path: '/admin',
secure: true
});
//cookie的value为对象
res.cookie('cart', { items: [1,2,3] });
前端表单->后端接收到文件本身->保存到服务器上->给数据库记录文件一些信息(如:文件路径)->库返回给nodejs相关信息->nodejs返回给前端
前端:
<form enctype="multipart/form-data" action="" method="post">
<input type=file name="fieldname" />
form>
实现
multer->文件名会随机->fs模块改名->path系统模块解析磁盘路径
后端:multer 接受 form-data编码数据
multer 接受 form-data编码数据,所以,要求前端携带时注意一下,如:
<form enctype="multipart/form-data" />
使用
//1 引入(在app.js里)
let multer = require('multer');
//2 实例化
let objMulter = multer({ dest: './upload' }); //dest: 指定 保存位置(存到服务器)
//安装中间件,
app.use(objMulter.any()); //允许上传什么类型文件,any 代表任何类型
中间件扩展了req请求体 req.files
app.post('/reg',(req,res)=>{
req.files//为一个数组,取值时注意
})
fieldname: 表单name名
originalname: 上传的文件名(浏览器端选择的文件的名字)
encoding: 编码方式
mimetype: 文件类型
buffer: 文件本身
size:尺寸
destination: 上传后,文件保存的路径 (服务器端的路径)
filename: 上传后,保存后的文件名 不含后缀
path: 上传后,保存磁盘路径+保存后的文件名 不含后缀
前端使用form发送请求代码
<form action="/upload" enctype="multipart/form-data" method="post" >
<input type="text" name="username" >
<input type="file" name="files" >
<input type="submit" value="上传">
form>
前端使用ajax发送请求:
<body>
<form action="regSave" method="post" >
用户名<input type="text" name="username" ><br/>
头像:
<img style="width:50px;height:50px" id="logoImg" />
<input type="file" id="photoFile" style="display: none;" onchange="upload()">
<a href="javascript:void(0)" onclick="uploadPhoto()">选择图片a>
<input name="logo" type="hidden" id="logoInput" > <br/>
<input type="submit" value="注册" >
form>
body>
html>
<script src="js/jquery-3.2.1.min.js">script>
<script>
function uploadPhoto() {
$("#photoFile").click();//选择文件的按钮
}
//上传
function upload(){
if ($("#photoFile").val() == '') {
return;
}
console.log($("#photoFile").val());
var formData = new FormData();
formData.append('photo', document.getElementById('photoFile').files[0]);
$.ajax({
url:"/upload",
type:"post",
data:formData,
contentType:false,
processData:false,
success:function(str){
console.log(str);//图片文件路径
$("#logoImg").attr("src",str);
$("#logoInput").val(str);
}
});
};
script>
客户端渲染(BSR:Browser Side Render)
客户端渲染:就是客户端在操作DOM.
渲染过程:在服务端放了一个html页面,客户端发起请求,服务端把页面发送过去,客户端从上到下依次解析,如果在解析的过程中,发现ajax请求,再次向服务器发送新的请求,客户端拿到ajax
响应的结果,渲染在页面上,这个过程中至少和服务端交互了两次
缺点:请求次数会增加,如果渲染逻辑复杂,数量大的话,尽量不要使用客户端渲染。
优点:网络上传输的数据量小,局部刷新
服务端渲染(SSR)
渲染过程:前端发送请求,服务器端从数据库中拿出数据,通过render()函数,把数据渲染在模板(ejs)里,产生了HTML代码,把渲染结果发给了前端,整个过程只有一次交互。
优点:提高渲染速度
缺点:网络上传输的数据量大了,页面全部刷新。
大多数网站里,既有服务端渲染又有客户端渲染 。
1)、客户端渲染不利于 SEO 搜索引擎优化,服务器端渲染有利于SEO搜索引擎优化
2)、服务端渲染是可以被爬虫抓取到的,客户端异步渲染是很难被爬虫抓取到的
SEO(Search Engine Optimization):搜索引擎优化
作用:提升网站关键词排名,提高访问量
1、网页中大量采用图片或者Flash等富媒体(Rich
Media)形式,没有可以检索的文本信息,而SEO最基本的就是文章SEO和图片SEO;
2、网页没有标题,或者标题中没有包含有效的关键词;
3、网页正文中有效关键词比较少(最好自然而重点分布,不需要特别的堆砌关键词);
4、网站导航系统让搜索引擎“看不懂”;
5、大量动态网页影响搜索引擎检索; 6、没有被其他已经被搜索引擎收录的网站提供的链接;
7、网站中充斥大量欺骗搜索引擎的垃圾信息,如“过渡页”、“桥页”、颜色与背景色相同的文字;
8、网站中缺少原创的内容,完全照搬硬抄别人的内容等。 9、网站地图,网站日记提取蜘蛛爬行轨迹。