socket.io 和会话?

Posted

技术标签:

【中文标题】socket.io 和会话?【英文标题】:socket.io and session? 【发布时间】:2011-06-06 04:16:18 【问题描述】:

我正在使用 express 框架。我想从 socket.io 获取会话数据。我尝试使用 client.listener.server.dynamicViewHelpers 数据表达 dynamicHelpers,但我无法获取会话数据。有没有一种简单的方法可以做到这一点?请看代码

app.listen(3000);

var io = require('socket.io');
var io = io.listen(app);

io.on('connection', function(client)
    // I want to use session data here
    client.on('message', function(message)
        // or here
    );
    client.on('disconnect', function()
        // or here
    ); 
);

【问题讨论】:

或者可以使用这个非常好的帖子:danielbaulig.de/socket-ioexpress @F***oPS - 不再起作用 - connect 不再提供它所依赖的 parseCookie 方法。 @UpTheCreek - 由于 connect 不再使用 parseCookie 方法,这怎么可能? @Aust - 好问题,我不知道现在最好的方法是什么。这真是一团糟。令人讨厌的是,大多数解决方法的讨论也都集中在 socket.io 上(不是每个人都在使用 socket.io!)。现在有一个 parseSignedCookie 函数,但它也是私有的,所以它也有破坏更改的风险。 对于较新版本的 Socket.IO (1.x) 和 Express (4.x),请检查这个 SO 问题:***.com/questions/25532692/… 【参考方案1】:

这不适用于通过 flashsocket 传输的套接字(它不会向服务器发送所需的 cookie),但它可靠地适用于其他一切。我只是在我的代码中禁用了 flashsocket 传输。

为了使其工作,在 express/connect 端,我明确定义了会话存储,以便我可以在套接字中使用它:

MemoryStore = require('connect/middleware/session/memory'),
var session_store = new MemoryStore();
app.configure(function () 
  app.use(express.session( store: session_store ));
);

然后在我的套接字代码中,我包含了连接框架,因此我可以使用它的 cookie 解析从 cookie 中检索 connect.sid。然后我在具有 connect.sid 的会话存储中查找会话,如下所示:

var connect = require('connect');
io.on('connection', function(socket_client) 
  var cookie_string = socket_client.request.headers.cookie;
  var parsed_cookies = connect.utils.parseCookie(cookie_string);
  var connect_sid = parsed_cookies['connect.sid'];
  if (connect_sid) 
    session_store.get(connect_sid, function (error, session) 
      //HOORAY NOW YOU'VE GOT THE SESSION OBJECT!!!!
    );
  
);

然后您可以根据需要使用会话。

【讨论】:

在最新版本的 socket.io-node 中似乎已经删除了 socket_client.request 当心...现在有新的惯例可以这样做...我建议改用 Socket.IO 身份验证。查看@Jeffer 的帖子 不幸的是,这将不再起作用 - parseCookie 不再是连接工具的一部分。显然它从来都不是公共 API 的一部分。有一个混乱的选择 - parseSignedCookie,但这也是私有的,所以我猜它也有消失的风险.. 现在我正在考虑这个......为什么不将 cookie 的 store 和 socket 的 store 设置为同一个 store?【参考方案2】:

Socket.IO-sessions 模块解决方案通过在客户端(脚本)级别公开会话 ID,将应用暴露于 XSS 攻击。

改为检查此solution(对于 Socket.IO >= v0.7)。请参阅文档here。

【讨论】:

@Jeffer - 第二个解决方案将不再适用于当前版本的连接。 -1 socket.io 是公开会话 ID,而不是该模块。这没什么大不了的,因为会话 ID 无论如何都存储在客户端的 cookie 中......而且该教程不适用于最新版本的 Express。 您的解决方案链接只是重定向到socket.io github 页面..?【参考方案3】:

我建议不要完全重新发明***。你需要的工具已经是一个 npm 包了。我想这就是你需要的:session.socket.io 这些天我正在使用它,我想它会非常有帮助!将 express-session 链接到 socket.io 层会有很多好处!

【讨论】:

这是一个更新的模块,它支持 socket.io >= 1.0 github.com/xpepermint/socket.io-express-session的 socket.io-express-sessions 【参考方案4】:

编辑:在尝试了一些不起作用的模块之后,我实际上已经编写了自己的库来执行此操作。无耻的插件:去https://github.com/aviddiviner/Socket.IO-sessions查看。出于历史目的,我将把我的旧帖子留在下面:


我非常巧妙地完成了这项工作,而无需按照上述 pr0zac 的解决方案绕过 flashsocket 传输。我也在 Socket.IO 中使用 express。方法如下。

首先,将会话 ID 传递给视图:

app.get('/', function(req,res)
  res.render('index.ejs', 
    locals:  
      connect_sid: req.sessionID
      // ...
    
  );
);

然后在您看来,将其与 Socket.IO 客户端链接:

<script>
  var sid = '<%= connect_sid %>';
  var socket = new io.Socket();
  socket.connect();
</script>
<input type="button" value="Ping" onclick="socket.send(sid:sid, msg:'ping');"/>

然后在您的服务器端 Socket.IO 侦听器中,将其拾取并读取/写入会话数据:

var socket = io.listen(app);
socket.on('connection', function(client)
  client.on('message', function(message)
    session_store.get(message.sid, function(error, session)
      session.pings = session.pings + 1 || 1;
      client.send("You have made " + session.pings + " pings.");
      session_store.set(message.sid, session);  // Save the session
    );
  );
);

就我而言,我的session_store 是Redis,使用redis-connect 库。

var RedisStore = require('connect-redis');
var session_store = new RedisStore;
// ...
app.use(express.session( store: session_store ));

希望这对在搜索 Google 时找到这篇文章的人有所帮助(就像我一样;)

【讨论】:

从安全角度来看,将会话 ID 放在客户端 html 中并不是一个好主意... 当会话 ID 已经存储在本地 cookie 中时,为什么将会话 ID 放在 HTML 中是个坏主意? 因为设置为 HttpOnly cookie 时无法从 javascript 访问 cookie。通过将 session.sid 放入 HTML 中,您可以为攻击者提供他们在 DOM 中所需的一切。【参考方案5】:

看到这个:Socket.IO Authentication

我建议不要通过client.request...client.listener... 获取任何内容,因为它们不直接附加到client 对象并且始终指向最后登录的用户!

【讨论】:

【参考方案6】:

查看 Socket.IO-connect

在 Socket.IO-node 周围连接 WebSocket 中间件包装器 https://github.com/bnoguchi/Socket.IO-connect

这将允许您在使用 Socket.IO 事件处理程序处理之前将 Socket.IO 请求向下推送到 Express/Connect 中间件堆栈,从而使您能够访问会话、cookie 等。虽然,我不确定它是否适用于所有 Socket.IO 的传输。

【讨论】:

不幸的是该模块仍在使用socket.io的v0.6【参考方案7】:

您可以使用 express-socket.io-session 。

与 socket.io 共享基于 cookie 的快速会话中间件。适用于 express > 4.0.0 和 socket.io > 1.0.0,并且不会向后兼容。

为我工作!!

【讨论】:

嘿。您将如何在前端使用会话值?我在 npm 文档中看不到它们。【参考方案8】:

你可以看看这个:https://github.com/bmeck/session-web-sockets

或者你也可以使用:

io.on('connection', function(client)  
  var session = client.listener.server.viewHelpers; 
  // use session here 
);

希望这会有所帮助。

【讨论】:

我知道 session-web-sockets 但我不想为此使用库,我正在寻找一个简单的解决方案。我试过client.listener.server.viewHelpers;但它返回了这个: 虽然起初这似乎可行,但它会导致竞争条件。我建议你完全避免它。【参考方案9】:

我不确定我做得对。 https://github.com/LearnBoost/socket.io/wiki/Authorizing

通过握手数据,您可以访问 cookie。在 cookie 中,您可以获取 connect.sid,它是每个客户端的会话 ID。然后使用 connect.sid 从数据库中获取会话数据(我假设你使用的是 RedisStore)

【讨论】:

这正是要走的路,但你不酷,所以你不能得到堆栈溢出点。 github.com/tcr/socket.io-session 和 github.com/functioncallback/session.socket.io 我喜欢第一个更好一点,它更干净。第二个记录得更好。 @TJ 对此我很抱歉,但你知道答案是 2 年前吗?而且现在可能行不通了 @TanNguyen 我知道,这就是我通知您的原因,以便您可以更新答案,而不是将人们指向死链接 @TJ 谢谢你。不幸的是,由于 2 年前的性能问题,我离开了 socket.io。因此,我不知道socket.io中当前处理会话的方式是什么【参考方案10】:

对于未来的读者 - 有一种优雅而简单的方法可以使用 express-session 访问 socket.io 中的会话。来自 socket.io 文档:

大多数现有的 Express 中间件模块应该与 Socket.IO 兼容,您只需要一个小包装函数来使方法签名匹配:

 const wrap = middleware => (socket, next) => middleware(socket.request, , next);

结束请求-响应周期并且不调用 next() 的中间件函数将不起作用。

快速会话示例:

const session = require("express-session");
io.use(wrap(session( secret: "cats" )));
io.on("connection", (socket) => 
   const session = socket.request.session; // here you get access to the session :)
);
 

【讨论】:

以上是关于socket.io 和会话?的主要内容,如果未能解决你的问题,请参考以下文章

PHP + socket.io(会话、授权和安全问题)

Socket.io 和会话数据

Socket.io 1.0.5:如何保存会话变量?

没有 express.js 的 Socket.io 会话?

无法从带有 Socket.IO 的 cookie 中获取 Express 会话 ID

与 socket.io 一起使用时 express-session 未设置会话 cookie