在Express应用程序中validationSocket.IO客户端

我有一个快速应用程序启动并运行与Passport.js(与MongoDB后端)的身份validation。

一切都很好,但现在我面临另一个挑战:

我想在我的项目中有一些“聊天”function,为此我使用Socket.IO(实时传递消息)。

该页面在加载之前validation用户是否已login,但仍然可以被绕过。

我希望Socket.IOstream得到保护和授权。

如何将Socket.IO聊天系统集成到基于Passport.js的身份validation中?

我不确定如何护照工作,但假设它在客户端设置一个cookie与他们的会话ID然后下面的解决scheme应该工作。 这看起来很不舒服,但我还没有看到更优雅的解决scheme。

var connect = require('express/node_modules/connect'), parseSignedCookie = connect.utils.parseSignedCookie, Cookie = require('express/node_modules/cookie'), store = YOUR_SESSION_STORE_INSTANCE, // ie 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%确定,但如果这不正确地拿起会话,您可能不得不将上面使用的会话存储更改为护照的会话存储,而不是默认的快速存储或您正在使用的任何。

希望有所帮助。 如果这样做,或者如果你find正确的解决scheme,请张贴你的发现,因为我们将来可能会转移到护照,知道如何修补我们现有的代码将是很好的。

编辑:经过一些更多的戳后,看起来像从上面显示的cookie中获取会话数据后,您将不得不find用户ID属性,并将该数据传递给护照。 他们在http://passportjs.org/guide/configure/上显示的示例是:

 passport.deserializeUser(function(id, done) { User.findById(id, function(err, user) { done(err, user); }); }); 

编辑2:另一种select是完全避开这个问题。 在实现上面列出的解决scheme之前,我们走了一条不同的路线,其中包含一次存储在redis中的令牌。 在高层次上,这个过程像这样工作:

  1. 客户端首先通过常规的HTTP请求从服务器请求一个令牌(实现为uuid)。 这通过express的中间件路由请求,并且可以轻松访问所有的会话数据。
  2. 生成令牌时,将其作为键值对存储在redis中,其中令牌是键,会话数据是值。
  3. 然后将令牌传回给socket.io客户端作为初始连接“升级”请求时作为GET参数附加到url的用户。
  4. 当socket.io接收到授权请求而不是validationcookie时,它会parsingURL,将令牌作为GET参数popup,并尝试对由令牌键入的键值对进行查询。 如果redis查询失败或返回空数据,则拒绝授权请求。 如果redis请求成功,那么您可以完全访问所有会话数据,现在可以删除redis中的键值对。

这里可能存在的问题是,你需要强制socket.io客户端在每次连接尝试时强制一个新的连接。 否则,它会尝试使用相同的连接,因此使用相同的标记。 如果在validation后删除令牌,则会阻止套接字重新连接。 根据您的应用程序,这可能是所需的行为。 这是为了我们的,所以我们保持原样,但仍然值得了解。

这种方法也使得你的WSauthentication机制独立于你的WS库。 由于安全原因,Sockjs不提供对连接请求的cookie访问,所以这种方法也使得我们从socket.io切换到sockjs更容易。

如果您正在开发基于Express ver 4.x和Socket.io ver 1.x的应用程序,则可能需要阅读以下文章: http ://mykospark.net/2014/07/authentication-with-socket-io- 1-0和-EXPRESS-4-0

在我的情况下,authentication程序的代码如下所示:

 io.use(function(socket, next) { var handshake = socket.handshake; if (handshake.headers.cookie) { var req = { headers: { cookie: handshake.headers.cookie, } } cookieParser(config.session.secret)(req, null, function(err) { if (err) { return next(err); } var sessionID = req.signedCookies[config.session.name] || req.cookies[config.session.name]; var sessionStore = new MongoStore({ db: global.db}); sessionStore.get(sessionID, function (err, session) { if (err) { return next(err); } // userData bellow is written once the Express session is created if (session && session.userData) { next(); } else { return next(new Error('Invalid Session')); } }) }); } else { next(new Error('Missing Cookies')); } });