今天做到聊天室问题的时候,登录成功保存或更新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的类型获取验证