使用 Express.js v4 和 Socket.io v1 的会话
Posted
技术标签:
【中文标题】使用 Express.js v4 和 Socket.io v1 的会话【英文标题】:Using sessions with Express.js v4 and Socket.io v1 【发布时间】:2014-09-26 09:47:17 【问题描述】:如何在 express.js 中保存会话数据并在 socket.io 事件中访问它?
我正在使用 express.js v4、socket.io v1 和基本的 express-session 中间件开发一个 webapp。
我花了几个小时试图弄清楚这一点,但 Stack Overflow 上的所有当前答案仅适用于 express v3 和 socket.io v0.9。不幸的是,我不能使用 express.io,因为它只是一个使用这些旧版本的包装器。
我目前的解决方案是彻底破解:
app.get('/auth', function(req, res)
if(verified(req.query))
authed[req.sessionID] = true;
);
io.sockets.on('connection', function(websocket)
var cookies = cookie.parse(websocket.handshake.headers.cookie);
var decrypted = cookieParser.signedCookies(cookies, random);
var sessionID = decrypted['connect.sid'];
websocket.on('input', function(input)
if(authed[sessionID])
// Do stuff...
);
);
我将我的“会话数据”作为基于会话 ID 的键/值存储保存在对象中。这适用于单进程应用程序,但它确实不是一个好的解决方案。它实际上并没有让我访问保存在 req.session 中的任何内容,如果进程结束,我保存的所有数据都将丢失。
最重要的是,我需要加载第 3 方 cookie 包来解析来自 socket.io 的 cookie 字符串。 cookie-parser 的新版本似乎取消了从字符串中解析 cookie 的功能。至少,它没有记录在案。
一定有更好的方法!
编辑:最后决定用express redis,在socket.io中写了一个函数,根据session ID从redis中获取信息。
【问题讨论】:
你能检查我的问题吗? superuser.com/questions/985825/… 【参考方案1】:您可以将会话存储在 Memcached 或 Redis 中。然后,您可以从其中任一商店获取会话数据。
memcache 和 redis 包都可用于 nodejs。
还请注意,您可以在 socket.io 中使用中间件进行身份验证。然后您不必将身份验证逻辑放入您的连接事件处理程序中。
var authorization = require('./socket/authorization')(app);
io.use(authorization.authorize);
作为示例,这个 memcached auth 内容在我们的例子中是读取我们的 php 存储的 cookie。
var memcached = require('memcached'),
cookie = require('cookie),
debug = require('debug')('socket.io:authorization');
module.exports = function(app)
var authorize = function(socket, next)
var handshakeData = socket.request;
if (handshakeData.headers.cookie)
handshakeData.cookie = cookie.parse(handshakeData.headers.cookie);
if (typeof handshakeData.cookie['node'] === 'undefined')
next(new Error('No cookie transmitted.'));
else
var loginEndIndex = handshakeData.cookie['node'].indexOf(',');
handshakeData.node = handshakeData.cookie['node'].slice(0, loginEndIndex);
var memcached = new Memcached(app.config.memcached.server, app.config.memcached.options);
memcached.on('failure', function(details)
debug('Server: %s went down due to %s', details.server, details.messages.join(' '));
);
memcached.on('reconnecting', function(details)
debug('Total downtime caused by server %s: %sms', details.server, details.totalDownTime);
);
memcached.get(handshakeData.cookie['PHPSESSID'], function(err, result)
if (!err && result !== false)
var pipeIndex = result.indexOf('|'),
phpData = result.slice(pipeIndex + 1),
obj = php.unserialize(phpData);
if (handshakeData.node === obj.userLogin)
debug('coockie-accepted: %s, %s', handshakeData.node, obj.userLogin);
next();
else
debug('cookie-revoked; %s, %s', handshakeData.node, obj.userLogin);
next(new Error('Cookie is invalid.'));
else
debug('error: %s', err);
next(new Error('Cookie is invalid.'));
memcached.end();
);
else
debug('error: No cookie transmitted.');
next(new Error('No cookie transmitted.'));
;
return
authorize: authorize
;
;
【讨论】:
【参考方案2】:我在使用 express.js 4.0 和 socket.io 0.9 时遇到了类似的问题。为了解决我的问题,我用自己的函数设置了“授权”过程,这是对我在网上找到的一些解决方案的修改。在此函数中,您将会话添加到数据属性并从套接字的握手属性访问它。看看代码。
我在 sockets 文件夹中创建了 index.js 和这个内容:
sio.set('authorization', function(data, accept)
/* NOTE: To detect which session this socket is associated with,
* we need to parse the cookies. */
if (!data.headers.cookie)
return accept(null, true);
data.cookie = cookie.parse(data.headers.cookie);
data.cookie = parse.signedCookies(data.cookie, sessionContainer.secret);
data.sessionID = data.cookie[sessionContainer.key];
sessionContainer.store.get(data.sessionID, function(err, session)
if (err)
return accept('Error in session store.', false);
else if (!session)
return accept('Session not found.', false);
if(!session.username)
return accept('Session not authenticated', true);
data.session = session;
return accept(null, true);
);
);
然后使用session中存储的数据:
sio.sockets.on('connection', function (socket)
var hs = socket.handshake;
/* NOTE: At this point, you win. You can use hs.sessionID and
* hs.session. */
if(hs.sessionID)
// logged in user
console.log('A socket with sessionID '+hs.sessionID+' connected.');
// here you can access whatever you stored in the session
console.log('User ' + hs.session.username);
socket.emit('news', hello: 'world' );
socket.on('my other event', function (data)
console.log(data);
);
clientSockets[hs.sessionID] = socket;
// handle the disconnect
socket.on('disconnect', function ()
if(clientSockets[hs.sessionID])
console.log('deleted unused socket ' + hs.sessionID);
delete clientSockets[hs.sessionID];
);
);
您可以在以下链接中找到整个项目 https://github.com/landreus/dimiblog/blob/master/sockets/index.js
希望对你有帮助!
【讨论】:
以上是关于使用 Express.js v4 和 Socket.io v1 的会话的主要内容,如果未能解决你的问题,请参考以下文章
使用 express.js 和 socket.io 构建推送通知系统的最佳方法
javascript Express.js和Socket.io使用相同的端口