nodejs session的原理
Cookie
HTTP协议是没有状态的,但是很多情况下是需要保存一些信息的。比如在用户登录后再次访问网站,没法判断用户是否已经登陆过。因此在这中情况下,我们需要一种数据结构来保存用户信息。于是Cookies就诞生了。
cookies用于在浏览器段保存用户信息。
cookies的特点如下:
- 保存在客户端浏览器
- 大小最大为4Kb
- 如果使用了cookies,访问域名时,浏览器会带上这个域名的cookies
但用户每次向服务器提交信息时都会带上Cookis。Coolies的特性非常不好,比如要访问的是服务器上的静态资源,比如图片,改访问并不需要确认用户,然而浏览器还是会发送Cookis给服务器。
Session
Session的作用和Cookie差不多,但是Session是保存在服务器端的。前面提到用户通过Cookie向服务器提交用户信息,服务器拿到用户信息后该怎么验证呢?查询一下数据库??这样可以实现,但是如果每个用户每次访问都要提交从数据库验证一次,那么将对服务器性能的极大浪费。所以服务器端保存Session用来验证用户身份的合法性。
Session的创建循序
- 生成全局唯一标示符
- 开辟数据存储空间。一般会在内存中开辟一块空间建立存储Session的数据结构,但是这样会有弊端:系统掉电,那么服务器端的Session将全部丢失。所以一般情况下会将Session保存在数据库或者文件夹中。
- 将Session的全局唯一标示符发送给客户端。
现在的问题是服务器怎么将Session的标示符发送给客户端呢。根据HTTP协议,数据的发送可以放在请求行、头域或Body里。
服务器发送给客户端浏览器Session的唯一标示符保存在客户端的Cookies中。
Set-Cookie
服务器返回浏览器的请求中设置Cookie。
{
"Set-Cookie": "session=r@rdegges.com"
}
服务器会返回一个set-cookie的消息,通知浏览器要设置cookie了,于是浏览器会根据set-cookie里的字段来设置信息了,比如上图的信息就会设置session=r@rdegges.com
实战
现在我们用client-session中间件来配置Session
-
安装模块
var session = require('client-sessions');
-
配置session
app.use(session({
cookieName: 'session',
secret: 'random_string_goes_here', //一个随机字符串,因为客户端的数据都是不安全的,所以需要进行加密
duration: 30*60*1000, //session的过期时间,过期了就必须重新设置
activeDuration: 5* 60*1000, // 激活时间,比如设置为30分钟,那么只要30分钟内用户有服务器的交互,那么就会被重新激活。
}))
在Session中保存用户信息
app.post('/login',function(req,res){
User.findOne({email:req.body.email}, function(err,user){ //数据库中查找改用户
if(!user){ //没有找到
res.render('login.jade',{error:'用户名或密码错误!'})
}else{
if(req.body.password == user.password){
req.session.user == user //将user信息保存到Session中
res.redirect('/dashboard')
}
}else{
res.render('login.jade',{error:'用户名或密码错误!'})
}
})
})
session层中间件
我们可以会在对每个请求做如下的检查,但是我们完全可以不必这样做。
app.use(function(req, res, next) {
if (req.session && req.session.user) {
User.findOne({ email: req.session.user.email }, function(err, user) {
if (user) {
req.user = user;
delete req.user.password; // delete the password from the session
req.session.user = user; //refresh the session value
res.locals.user = user;
}
// finishing processing the middleware and run the route
next();
});
} else {
next();
}
});
如果需要是用户登录后才能访问的页面,那么我们可以设计一个检查是否登录的中间函数。
function requireLogin(req,res,next){
if(!req.user){
res.redirect('/login')
}else{
next();
}
}
app.get('/dashboard',requireLogion,function(req,res){
res.render('dashboard.jade)
})
安全性
我们可以在登出时重置Session
app.get('/logout',function(req,res){
req.session.reset()
res.redirect('/')
})
总结
Cookie和Session有各自的优缺点
- 应用场景
Cookie的典型应用为RememberMe 服务即用户的账户信息通过cookie的形式保存在客户端,当用户再次请求匹配的url时,账户信息会被传送到服务器端,交给相应的程序完成自动登录功能。当然亦可以保存一些客户端信息,如页面布局和搜索历史等。
Session的典型应用场景是用户登录某网站之后,将其登录信息放入session,在以后的每次请求中查询相应的登录信息以确保该用户合法。当然还是有购物车等等经典场景;
- 安全性
cookie将信息保存在客户端,如果不进行加密的话,无疑会暴露一些隐私信息,安全性很差,一般情况下敏感信息是经过加密后存储在cookie中,但很容易就会被窃取。而session只会将信息存储在服务端,如果存储在文件或数据库中,也有被窃取的可能,只是可能性比cookie小了太多。
Session安全性方面比较突出的是存在会话劫持的问题,这是一种安全威胁,这在下文会进行更详细的说明。总体来讲,session的安全性要高于cookie;
- 性能
Cookie存储在客户端,消耗的是客户端的I/O和内存,而session存储在服务端,消耗的是服务端的资源。但是session对服务器造成的压力比较集中,而cookie很好地分散了资源消耗,就这点来说,cookie是要优于session的;
- 时效性
Cookie可以通过设置有效期使其较长时间内存在于客户端,而session一般只有比较短的有效期(用户主动销毁session或关闭浏览器后引发超时);
- 其他
Cookie的处理在开发中没有session方便。而且cookie在客户端是有数量和大小的限制的,而session的大小却只以硬件为限制,能存储的数据无疑大了太多。
参考https://segmentfault.com/a/1190000010837077