这两天一直在研究session的问题,session属于开发中老生常谈的问题,但是我却一直搞的很模糊。DoraCMS 使用了最基本的 session来记录登录用户信息,但是并没有对session进行管理(超时控制,清除,存储等)。网上很普遍的一种方式是使用redis,得益于朋友博客的源码,自己也研究了一下,于是把session重新处理了下。

    Redis是一个非常适合用于Session管理的数据库。第一,它的结构简单,key-value的形式非常符合SessionID-UserID的存储;第二,读写速度非常快;第三,自身支持数据自动过期和清除;第四,语法、部署非常简单。基于以上原因,很多Session管理都是基于Redis实现的。
Express已经将Session管理的整个实现过程简化到仅仅几行代码的配置的地步了,你完全不用理解整个session产生、存储、返回、过期、再颁发的结构,使用Express和Redis实现Session管理,只要两个中间件就足够了:

除此之外,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
}));


2、在用户登录成功之后,将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天
}



3、 在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];


4、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 源码