Sails.js + Passport.js通过Websockets进行身份验证

33
当我在使用Sails.js和Passport.js时,通过websocket请求时,req对象上不存在isAuthenticated方法。请问这是为什么?
4个回答

25

或者,您可以劫持“router:request”事件,为套接字请求插入passport。 我在“config / bootstrap.js”中执行此操作:

或者,您可以劫持“router:request”事件,为套接字请求插入passport。 我在“config / bootstrap.js”中执行此操作:

module.exports.bootstrap = function (cb) {

  var passport = require('passport'),
    initialize = passport.initialize(),
    session = passport.session(),
    http = require('http'),
    methods = ['login', 'logIn', 'logout', 'logOut', 'isAuthenticated', 'isUnauthenticated'];

  sails.removeAllListeners('router:request');
  sails.on('router:request', function(req, res) {
    initialize(req, res, function () {
      session(req, res, function (err) {
        if (err) {
          return sails.config[500](500, req, res);
        }
        for (var i = 0; i < methods.length; i++) {
          req[methods[i]] = http.IncomingMessage.prototype[methods[i]].bind(req);
        }
        sails.router.route(req, res);
      });
    });
  });
  cb();
};

采用这种方法,您无需在策略中特别处理检查套接字请求的身份验证。但是,您仍需要通过Express中间件连接护照以用于非套接字请求。


1
我的问题出在需要身份验证的PUT和POST请求上,只有@xdissent的答案解决了它。 - rowanu
1
这是一个很好的解决方法--以下是来自lib/router常见问题解答的原因:
  • 当HTTP请求到达服务器时,它是否会先经过Sails路由器再经过Express路由器?
  • 不会-它只会经过Express路由器。
  • 好的..那么哪些请求会经过Sails路由器呢?
  • 发送到其他附加服务器的请求,这些服务器没有自己的路由器,例如Socket.io解释器,将会经过Sails路由器的通配符处理程序,然后与附加服务器通信并模拟适当的路由。
- mikermcneil
这个完美地运行了。它甚至允许我通过Websockets进行身份验证,因此我不必使用XHR请求。当处于socket模式时,req缺少一些特定于express和其中间件的东西,正如所提到的那样。 - geilt
只是好奇,return sails.config[500](500, req, res); 这一行是在做什么?在 Sails 0.10.x 下,现在应该改为 return serverError(); 吗? - Dave Sag
在Sails 0.11中,套接字服务器已经升级。有什么指针可以让它与Socket.IO 1.0一起工作? - amarprabhu
这里有一个在0.11版本上有效的解决方法。 - Alexis N-o

14
请尝试检查req.session.passport.user。 当已登录时,其中将包含用户信息,否则将为未定义。 对于任何类型的请求都适用于我。
我认为发生这种情况是因为在WebSocket请求的情况下,“req”实际上是虚拟请求对象。 它被创建并直接传递给Express的路由器,绕过了所有Express中间件,包括Passport的中间件。

1
完全正确-关于这在Sails核心中如何工作的解释,请查看lib/router中的README。这在未来版本的Sails中可能会简化-但首先还有一些其他考虑要解决(有关更多信息,请参见[问题#141](https://github.com/balderdashy/sails/pull/1431#issuecomment-35816845))。 - mikermcneil
虽然这解决了“已登录问题”,但我如何访问实际的用户对象呢?使用普通的http,passport正在运行一个反序列化用户函数,我可以从req.user中访问它。现在,使用socket连接,我没有得到任何用户对象。 - tkarls

11

@ataman说得很对。使用express.customMiddleware配置安装的Express中间件仅适用于Express HTTP请求。

要使护照适用于所有请求,请在您的策略中使用它:

// e.g. 
// config/policies.js
module.exports = {
  SomeController: {
    someaction: function somePassportMiddlewareFn() {}
  }
};

0

另一种扩展带有护照定义的方法login、logout等的socket.io req的方式是按照以下方式重写策略或中间件

module.exports = (req, res, next) ->
    if req.isSocket
        req = _.extend req, _.pick(require('http').IncomingMessage.prototype, 'login', 'logIn', 'logout', 'logOut', 'isAuthenticated', 'isUnauthenticated')
    middleware = passport.authenticate('bearer', { session: false })
    middleware(req, res, next)

这段代码有文件名吗?如果有,那么该文件会存储在哪个目录中? - Cody

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接