我不确定护照究竟是如何工作的,但假设它在客户端上设置了一个带有会话 ID 的 cookie,那么下面的解决方案应该可以工作。这看起来很老套,但我还没有看到更优雅的解决方案。
var connect = require('express/node_modules/connect'),
parseSignedCookie = connect.utils.parseSignedCookie,
Cookie = require('express/node_modules/cookie'),
store = YOUR_SESSION_STORE_INSTANCE, // i.e. redis-store, memory, or whatever
sessionKey = "YOUR SESSION KEY", // defaults to connect.sid
sessionSecret = "YOUR SESSION SECRET";
var verifyCookie = function(data, callback){
try{
var cookie = Cookie.parse(data.headers.cookie);
var sessionID = parseSignedCookie(cookie[sessionKey], sessionSecret);
store.get(sessionID, callback);
}catch(e){
callback(e);
}
};
// set up socket.io to validate cookies on an authorization request
// this assumes you've assigned your socket.io server to the io variable
io.configure(function(){
io.set("authorization", function(handshake, accept){
if(handshake.headers.cookie){
verifyCookie(handshake, function(error, session){
if(error || !session)
accept("Invalid authentication", false);
else
accept(null, true);
});
}else{
accept("Invalid authentication", false);
}
});
});
我在这里不能 100% 确定,但如果这不能正确获取会话,您可能需要将上面使用的会话存储更改为护照的会话存储,而不是默认的快速存储或您使用的任何内容。
希望对您有所帮助。如果这可行,或者如果您找到正确的解决方案,请发布您的发现,因为我们将来也可能会迁移到护照,并且很高兴知道如何修补我们现有的代码。
编辑:经过一番摸索后,看起来从 cookie 中获取会话数据后,如上所示,您必须找到用户 id 属性并将该数据传递给护照。他们在http://passportjs.org/guide/configure/ 显示的示例是:
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
编辑 2:另一种选择是完全回避这个问题。在实现上面列出的解决方案之前,我们走了一条不同的路线,其中涉及存储在 redis 中的一次性令牌。在高层次上,这个过程是这样工作的:
- 客户端首先通过常规 HTTP 请求从服务器请求令牌(实现为 uuid)。这通过 express 的中间件路由请求,并提供对所有会话数据的轻松访问。
- 生成令牌时,它作为键值对存储在 redis 中,其中令牌是键,会话数据是值。
- 令牌随后被传回给用户,socket.io 客户端在发出初始连接“升级”请求时将其作为 GET 参数附加到 url。
- 当 socket.io 收到授权请求而不是验证 cookie 时,它会解析 url,将令牌作为 GET 参数弹出,并尝试在 redis 中查询由令牌键入的键值对。如果 redis 查询失败或返回 null 数据,则您拒绝授权请求。如果 redis 请求成功,那么您可以完全访问所有会话数据,现在您可以删除 redis 中的键值对。
这里的一个可能问题是您需要强制 socket.io 客户端在每次连接尝试时强制建立一个新连接。否则,它会尝试使用相同的连接并因此使用相同的令牌。如果您在验证令牌后删除令牌,这将阻止套接字重新连接。根据您的应用程序,这可能是所需的行为。它是给我们的,所以我们保持原样,但它仍然值得了解。
这种方法还使您的 WS 身份验证机制独立于您的 WS 库。出于安全原因,Sockjs 不提供对连接请求的 cookie 的访问,因此这种方法也使我们从 socket.io 切换到 sockjs 更容易。