今天做到聊天室问题的时候,登录成功保存或更新mongodbsession信息,想要在socket对话的时候验证和获得session的信息,如果存在session,转发信息,否则返回一个提示并关闭socket连接。
关于mongodb存储session在之前已经讲述使用connect-mongo来管理session的信息,但是socket如何获得session的信息并且和前端的连接的socket handshake的cookie ID 一致。在网上找到了解决方案,不过只适合在connect-redis使用可以下载代码npm install session.socket.io预读代码,代码很少,我只修改了部分代码完成了想要的功能。代码如下:
module.exports = function(io, sessionStore, cookieParser, key) { key = key || 'connect.sid'; this.of = function(namespace) { return { on: function(event, callback) { return bind.call(this, event, callback, io.of(namespace)); }.bind(this) }; }; this.on = function(event, callback) { return bind.call(this, event, callback, io.sockets); }; this.getSession = function(socket, callback) { cookieParser(socket.handshake, {}, function (parseErr) { var sessionid = socket.handshake.cookies[key]; //由于cookie保存如下,mongodb保存的_id为sessionID的加密格式,为ypbxGhOzzAQDlsn3mmVGrO6A,获取想要的串就ok //s:ypbxGhOzzAQDlsn3mmVGrO6A.9rtRxhQu3r8ymOZ1s%2FzlfEWaZ9MSorSBobzy8CNhjh0 var sid = ''; if(sessionid) { sid = sessionid.split(':')[1].split('.')[0]; } sessionStore.get(sid, function (storeErr, session) { var err = resolve(parseErr, storeErr, session); callback(err, session); }); }); }; function bind(event, callback, namespace) { namespace.on(event, function (socket) { this.getSession(socket, function (err, session) { callback(err, socket, session); }); }.bind(this)); } function findCookie(handshake) { return (handshake.secureCookies && handshake.secureCookies[key]) || (handshake.signedCookies && handshake.signedCookies[key]) || (handshake.cookies && handshake.cookies[key]); } function resolve(parseErr, storeErr, session) { if (parseErr) return parseErr; if (!storeErr && !session) return new Error ('could not look up session by key: ' + key); return storeErr; } };
现在socket链接的时候使用如下代码
var SessionSockets = require('./session.socket.io');//也就是以上的代码片段 var sessionStore = new MongoStore({ url:settings.mongodb.host }); var cookieParser =express.cookieParser('world'); //当然这里还有很多配置 //jsessionid为云存储统一制定id,单机可要可不要参见http://blog.cloudfoundry.com/2013/01/24/scaling-real-time-apps-on-cloud-foundry-using-node-js-and-redis/ var sessionSockets = new SessionSockets(io,sessionStore,cookieParser,'jsessionid'); sessionSockets.on('connection', function (err,socket,session) { console.log('-session',session.jsessionid);//在登录的时候只要设置req.session.jsessionid就可以得到此ID })
终于,感觉上面的方法有些繁琐,于是另辟蹊径,果然找到了更加简易的方法,socket.io自带有一个握手验证方法authorization,这个方法在链接的时候验证是否登录成功,那我们可以根据会话成功修改成我们设定的sessionID,以便于我们在socket可以访问到。上代码:
//第二个参数和第三个参数和以上一样 module.exports = function (io,sessionStore,cookieParser) { //验证并设置session io.set('authorization', function(handshakeData, callback){ // 通过客户端的cookie字符串来获取其session数据 handshakeData.cookie = cookie.parseCookie(handshakeData.headers.cookie) var sessionid = handshakeData.cookie['connect.sid'];//这是默认的,可以在app.use(express.session({key:'userid'})的这个key来修改默认 if (sessionid) { //由于cookie保存如下,mongodb保存的_id为sessionID的加密格式,为ypbxGhOzzAQDlsn3mmVGrO6A,获取想要的串就ok //s:ypbxGhOzzAQDlsn3mmVGrO6A.9rtRxhQu3r8ymOZ1s%2FzlfEWaZ9MSorSBobzy8CNhjh0 var sid = ''; if(sessionid) { sid = sessionid.split(':')[1].split('.')[0]; } sessionStore.get(sid, function(error, session){ if (error) { // if we cannot grab a session, turn down the connection callback(error.message, false); } else { //console.log('session,',session) // save the session data and accept the connection handshakeData.session = session; callback(null, true); } }); } else { callback('nosession'); } }); //开始监听客户端连接 io.on('connection', function (socket) { console.log("Connection " + socket.id + " accepted."); //如下使用可以拿到session里的userid console.log('-session',socket.handshake.session.userid); //从客户端接受消息 socket.on('message',function(msg){ }) }) }
不过感觉最开始那种更全面点哈。特别是对cookie的类型获取验证