【问题标题】:How access session data (of node-client-sessions) on socket.io?如何访问 socket.io 上的会话数据(节点客户端会话)?
【发布时间】:2013-08-30 19:07:57
【问题描述】:

我的应用程序中的会话数据由node-client-sessions(如Using secure client-side sessions to build simple and scalable Node.JS applications 中的建议)处理,现在我有socket.io(websockets)来处理一些实时功能。我想通过握手时的会话数据对登录用户进行身份验证。但是 socket.io 在握手时给了我们这个handshakeData 对象,它并没有完全暴露请求对象。我需要访问请求的会话属性。有什么想法吗?

我正在使用expressjs (nodejs)。

更新

受@LaurentPerrin 的启发,我深入研究了客户端会话源代码,发现解码和编码功能暴露在外。也许不像直接弄乱我的会话对象那么容易,但到目前为止非常有效。

我的代码,到目前为止:

/*jslint node: true, es5: true, nomen: true, unparam: true */

'use strict';

var encode = require('client-sessions').util.encode,
    decode = require('client-sessions').util.decode,
    cookie = require('cookie'),

    cookieSettings = require('./persistors/cookieSettings'),

    authorized = {
        'me@domain.com': 1
    };

module.exports = function websocket(io) {
    io.set('authorization', function (handshakeData, callback) {
        var session_data;
        if (!handshakeData.headers.cookie) {
            callback({
                status: 'forbidden',
                reason: 'no session',
                source: 'socket_io'
            }, false);
            return;
        }
        session_data = decode(cookieSettings, cookie.parse(handshakeData.headers.cookie).session).content;
        if (authorized[session_data.email]) {
            handshakeData.session_data = session_data;
            callback(null, true);
        } else {
            // callback({
            //     status: 'forbidden',
            //     reason: 'unauthorized',
            //     source: 'socket_io'
            // }, false);
            callback(null, false);
        }
        return;
    });
    io.set('transports', ['websocket', 'flashsocket']);
    io.sockets.on('connection', function (socket) {
        console.log('connected')
        socket.on('credenciamento', function (data) {
            console.log(socket.handshake.session_data.email);
            socket.broadcast.emit('credenciamento', {
                inscrito_id: data.inscrito_id
            });
        });
    });
};

这绝不是完整的。但是授权部分似乎工作得很好。 =)

现在,关于回调函数。起初我像@LaurentPerrin 一样使用它,传递一个带有错误响应的对象。但它会产生警告。 Socket.io 认为发生了错误:

warn - handshake error [object Object]

所以在第二个时刻,我在未授权时将null 作为第一个参数传递:

info - handshake unauthorized

考虑到 socket.io 理解每一件事的方式,第二种方式在语义上似乎更正确。 =)

我选择第二种方式。自己挑一个。

【问题讨论】:

  • 感谢您提供有关公开编码/解码方法的信息!我想知道您是否让客户端会话完全可以使用套接字?我在问,因为在后端的套接字事件中更改会话对象时,似乎不可能更新 cookie(其中包含会话信息)。我可以切换到 LongPolling 但会失去套接字的好处,或者我可以为会话使用 Redis 后端但会失去客户端会话的好处。有什么线索吗?
  • @japrescott 我只需要授权,所以我认为我所做的不仅仅是授权。但是你不能修改“cookie”并再次编码吗?我认为它会起作用......好吧,让我知道!我会检查我的代码。现在这是一个老项目了......无论如何,您可能仍然需要 Redis,请记住:“立即撤销 Persona 会话与服务器端会话相比,客户端会话的主要缺点之一是服务器不再具有此功能销毁会话。”
  • 我的解决方案现在包括使用 cookiesession 来存储用户 ID,这样我就可以在未来永远检测到用户。一旦通过 db hit “授权”,用户数据就会存储在 redis 中,以供以后检索用户信息/会话。从那里开始可以信任进一步的请求,并且不需要数据库命中来验证用户,我可以直接从 redis 中获取并信任它的那个用户调用。但是中间人攻击向量仍然存在,但可以用 ssl 关闭。

标签: node.js session express socket.io


【解决方案1】:

不确定它是否完全相同,但我在我的情况下写了这个。请注意,我在 express 依赖项中直接 require 以避免版本问题。

var cookie = require('express/node_modules/cookie'),
    parseSignedCookie = require('express/node_modules/connect').utils.parseSignedCookie,
    parseJSONCookie = require('express/node_modules/connect').utils.parseJSONCookie;

…

io.set('authorization', authorizeSocket);

…

function authorizeSocket(handshake, done) {
  if (!handshake.headers.cookie)
    return done({status: 'forbidden', reason: 'no session', source: 'socket_io'}, false);

  var cookies = cookie.parse(handshake.headers.cookie),
      signed = cookies['your_session_cookie'];

  if (!signed)
    return done({status: 'forbidden', reason: 'tampered cookie', source: 'socket_io'}, false);

  var raw = parseSignedCookie(signed, 'your_session_secret'),
  json = parseJSONCookie(raw);

  if (!json || !json.passport || !json.passport.user)
    return done({status: 'forbidden', reason: 'bad session', source: 'socket_io'}, false);

  // finally...
  var user = json.passport.user;

  handshake.user = user;

  done(null, true);
}

【讨论】:

  • 我想明白了。但它适用于客户端会话吗?我的意思是,它似乎并没有公开我们自己解密 cookie 中会话数据的方法。每个请求都可以访问这个会话对象(而且它很棒)(而且使用 socket.io 离我的范围有点太远了......)。
  • 或许确实如此!您的回答是继续前进的灵感!非常感谢! (我仍然想访问会话对象,它是如此接近!=P)
  • 最后一次,谢谢。我主要是按照你给我看的方式做的。使用client-sessions 似乎更容易。我用一些代码和注意事项更新了我的答案。您可能感兴趣的是:将对象作为您的 done 函数的第一个参数传递意味着授权过程中存在错误。语义...不是授权错误吗? Socket.io 消息让我不以为然。
猜你喜欢
  • 2015-12-28
  • 2023-03-29
  • 1970-01-01
  • 2014-02-02
  • 2011-10-22
  • 2014-05-26
  • 1970-01-01
  • 2017-12-03
  • 2011-06-14
相关资源
最近更新 更多