使用Express.js v4和Socket.io v1的会话

时间:2014-08-03 22:55:46

标签: javascript node.js session express socket.io

如何在express.js中保存会话数据并在socket.io事件中访问它?

我正在使用 express.js v4 socket.io v1 和基本express-session中间件开发网络应用。

我花了几个小时试图解决这个问题,但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中保存的任何内容,如果流程结束,我保存的所有数据都将丢失。

最重要的是,我需要加载第三方cookie包来解析来自socket.io的cookie字符串。似乎新版本的cookie-parser取消了它从字符串中解析cookie的功能。至少,它没有记录。

必须有更好的方法!

编辑:最后,我决定使用express redis并在socket.io中编写一个函数,以便根据会话ID从redis获取信息。

2 个答案:

答案 0 :(得分: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
    };
};

答案 1 :(得分:0)

我使用express.js 4.0和socket.io 0.9时遇到了类似的问题。为了解决这个问题,我设置了授权'使用我自己的功能进行处理,这是我在网上找到的一些解决方案的修改。在此函数中,您将会话添加到data属性并从套接字的handshake属性访问它。看看代码。

我使用以下内容在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);
  });
});

然后使用会话中存储的数据:

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

希望它有所帮助!