这两天一直在研究session的问题,session属于开发中老生常谈的问题,但是我却一直搞的很模糊。DoraCMS 使用了最基本的 session来记录登录用户信息,但是并没有对session进行管理(超时控制,清除,存储等)。网上很普遍的一种方式是使用redis,得益于朋友博客的源码,自己也研究了一下,于是把session重新处理了下。
Redis是一个非常适合用于Session管理的数据库。第一,它的结构简单,key-value的形式非常符合SessionID-UserID的存储;第二,读写速度非常快;第三,自身支持数据自动过期和清除;第四,语法、部署非常简单。基于以上原因,很多Session管理都是基于Redis实现的。
Express已经将Session管理的整个实现过程简化到仅仅几行代码的配置的地步了,你完全不用理解整个session产生、存储、返回、过期、再颁发的结构,使用Express和Redis实现Session管理,只要两个中间件就足够了:
express-session
connect-redis
除此之外,redis 也是要装在服务器上的,具体怎么安装参考下这篇文章:
http://www.cnblogs.com/lxx/archive/2013/06/04/3116985.html
DoraCMS 使用redis管理session的方式也比较简单,这里只介绍原理,不列出全部代码:
1、安装必要的中间件 express-session, connect-redis
2、在app.js 中配置redis:
var session = require('express-session');
var RedisStore = require('connect-redis')(session);
app.use(session({
secret: Settings.session_secret,
store: new RedisStore({
port: Settings.redis_port,
host: Settings.redis_host,
ttl: 1800
}),
resave: true,
saveUninitialized: true
}));
3、在用户登录成功之后,将cookie记录入缓存中:
// 用户登录提交请求
router.post('/doLogin', function(req, res, next) {
var email = req.body.email;
var password = req.body.password;
var newPsd = DbOpt.encrypt(password,"dora");
User.findOne({email:email,password:newPsd},function(err,user){
if(user){
// 将cookie存入缓存
filter.gen_session(user, res);
console.log('------------登录成功------');
res.end("success");
}
else
{
res.end("error");
}
})
});
filter.gen_session 的实现:
function gen_session(user, res) {
var auth_token = user._id + '$$$$'; // 以后可能会存储更多信息,用 $$$$ 来分隔
res.cookie(settings.auth_cookie_name, auth_token,
{path: '/', maxAge: 1000 * 60 * 60 * 24 * 30, signed: true, httpOnly: true}); //cookie 有效期30天
}
4、 在app.js 中加入检查用户登录状态的方法:
app.use(filter.authUser);
``
实现:
exports.authUser = function (req, res, next) {
if (req.session.user) {
req.session.logined = true;
console.log('--------找到缓存------')
return next();
} else {
var auth_token = req.signedCookies[settings.auth_cookie_name];
console.log('--------找不到session------'+auth_token)
if (!auth_token) {
return next();
}else{
var auth = auth_token.split('$$$$');
var user_id = auth[0];
User.findOne({'_id' : user_id},function(err,user){
if(err){
console.log(err)
}else{
req.session.user = user;
req.session.logined = true;
return next();
}
})
}
}
};
``
原理大概是这样的,用户登录后,将用户Id记录到cookie中并设置过期时间,在每次请求页面,如果 session 为空,则通过:
var auth_token = req.signedCookies[settings.auth_cookie_name];
5、session 的清理:
router.get('/logout', function(req, res, next) {
req.session.destroy();
res.clearCookie(Settings.auth_cookie_name, { path: '/' });
res.end("success");
});
这种方式来查询是否有用户存储的cookie,如果有,则通过 auth_token 的方式去获取用户Id查询用户信息后存储到session中。因为cookie设置了超时时间,不论浏览器是否关闭或者服务器是否重启,cookie依然是存在的,所以只要没有超时,即使session丢到,通过cookie中存储的key和value值就可以重新找到用户信息并在此存入到session中。我大概是这样理解的,如果有误也请大神补充。
更详细的代码请参考 DoraCMS 源码