我有一个工作的php应用程序,我想在其中添加实时支持。我想使用nodejs / socket.io来添加这种功能。
我发现的第一个问题是如何在nodejs端正确授权用户(用户已经通过PHP会话在php后端进行了身份验证)。在nodejs端使用 socket.handshake.header.cookie 我可以解析并获取PHP会话ID,我可以通过redis / memcache / database进行身份验证(取决于我用来保存会话信息的内容)。
当用户只打开一个站点的选项卡/窗口时,一切看起来都很酷 - 当有更多并使用 session_regenerate_id()时,在nodejs中用户使用另一个sessionid键进行身份验证,因此我无法区分两个标签除了与它们连接的套接字ID以外的任何其他标签。当用户注销时,他不应该在任何选项卡上收到任何消息(因为他已经从该浏览器的每个选项卡/窗口中注销)。所以在注销消息(在注销PHP之前从浏览器发送的东西)我应该删除连接到授权用户ID的所有套接字连接。但是,如果用户登录两个设备(例如PC浏览器和ipad safaris),该怎么办?在一台设备上注销后,他不应该在他注销的设备上收到任何消息,而不是在每台设备上。 如何区分socket.io中不同设备/浏览器的连接?当然不使用 session_regenerate_id()会很有效,但如果我真的想要怎么办?使用此功能?
我遇到的另一个问题是安全问题(甚至问题)。我们假设应用程序中的授权用户可以看到页面 example.com/user1 (这是user1的新闻源),但看不到 example.com/user2 (例如,他)没有权利看到它)。我希望socket.io在用户访问 example.com/user1 时向浏览器发送更新消息,当用户在 example.com/user2 网站。在socket.io端,我可以读取引用地址(因此,当用户在user2站点上时,他没有得到任何socket.io连接)。问题是:我应该将引用地址与node.js端的已认证用户的权限进行比较吗?或者,node.js端的referer值是 safe ?在node.js端添加另一个db检查会减慢它(因为几乎每个请求都应该有相同的数据库检查)双方 - PHP和node.js)。
或者也许socket.io + PHP应用程序的整个概念以我提出的方式工作是错误的?
更新
我想我找到了一种方法来省略第一个问题的问题 - 基本上我只是添加另一个cookie(除了PHPSESSID)fe。名为NODESESSID,我在用户被授权时生成(fe。使用uniqid())。现在,node.js端的授权正在比较PHPSESSID和NODESESSID(两者必须匹配)。现在,当用户注销时,他将消息 logout 传递给socket.io,socket.io断开所有带有NODESESSID的套接字。这就像连接重新生成会话ID的好处而不是重新生成会话ID(但不容易受到会话固定的影响,不是吗?)。
答案 0 :(得分:1)
关于你的第二个问题:
如评论中所述,Referer并不安全。
我在我的应用程序中遇到了类似的问题,这就是它对我有用的方法。
首先,我有一个单页应用程序,其中所有流量都通过套接字,但这不是必需的。它也应该以您管理它的方式使用会话。
在nodejs onConnect中我询问后端用户是否经过身份验证,然后将用户ID存储到套接字对象(socket.data)中,并填充哈希映射以直接从userids查找套接字。
第二,我使用Redis并从nodejs(see redis pub/sub)订阅redis列表。 php后端使用userid将此列表中的消息推送到消息中。 nodejs接收此消息(例如,新的新闻订阅源项),在提到的散列映射中查找用户ID并将其发送到客户端。因此,用户只能获得他的授权。然后客户决定如何处理该消息。如果用户在他的Feed页面上,则可以添加该项目。如果用户使用其他人,则只需在页面上的其他位置添加通知即可。它也可能会丢弃它。
在php后端站点上,每次发生事件时都会将此消息发送到redis,需要在某个连接的客户端上显示。如果user1在user2的feed上发布,则新项目将存储在数据库中,同时作为消息发送到redis队列。此系统还有助于减少数据库负载,因为nodejs只需要查询数据库以确保已连接的用户已经过身份验证。
答案 1 :(得分:0)
实际上,您可以避免使用node.js,并使用phpdaemon,它用PHP编写并且工作得非常好。