【问题标题】:ExpressJs Passportjs de-serializes user object for every request to a routeExpressJs Passportjs 对路由的每个请求反序列化用户对象
【发布时间】:2016-03-20 13:35:23
【问题描述】:

我有一个 ExpressJS 应用程序,它使用 Passportjs 向 Facebook 进行身份验证,并且对于一个问题,一切都按预期运行。

我在/routes/ 下有vehicle.js,其中包含一些需要身份验证的路由(router.gets 和 router.posts),而另一些则不需要。如果用户已登录,则vehicle.js 处理的每个请求都会导致用户反序列化,即Mongoose 查找。 当向不需要身份验证的router.get 和/或router.post 发出请求时,如何避免这些不必要的Mongoose 查找?

我已经查过这个SO question 并没有解决我的问题(我已经在护照上面声明了静态资源,所以它们没有经过身份验证)。

Passportapp.js 中的配置如下所示:

// Configuring Passport
var passport = require('passport');
var expressSession = require('express-session');

app.use(expressSession({secret: 'thisIsSecret'}));
app.use(passport.initialize());
app.use(passport.session());

// Using the flash middleware provided by connect-flash to store messages in session
// and displaying in templates
var flash = require('connect-flash');
app.use(flash());

// Initialize Passport
var initPassport = require('./passport/init');
initPassport(passport);

//passing passport object could be the reason why all requested that are 
//mapped in vehicle cause user de-serialization. Not sure if there is any
//alternative approach than following line that passes passport??
var vehicle = require('./routes/vehicle')(passport);

以下isAuthenticated在vehicle.js

var isAuthenticated = function (req, res, next) {
  if (req.isAuthenticated())
    return next();
    // if the user is not authenticated then redirect him to the login page
    res.redirect('/vehicle/api/login');
}

后面是一系列处理logging inlogging outroutes,以及对vehicle的一些操作。

module.exports = function(passport) {
  router.get('/api/login', function(req, res) {
    res.render('vehicle/login', { message: req.flash('message') });
  });
  router.post('/api/login', passport.authenticate('login', {
    successRedirect: '/vehicle/api/list/mine',
    failureRedirect: '/vehicle/api/list',
    failureFlash : true
  }));
  ...
  ...
  ...
  router.post('/api/upload', isAuthenticated, function(req, res) {
    //this route needs to  be authenticated, so it works fine, 
    //deserialization done, mongoose lookup, no problem
  }); 
  router.get('/api/image/:vehicleId/:filename', function(req,res) {
    //this route does not need authentication, but causes User 
    //de-serialization and Mongoose lookup
  }); 
 return router;
}

是不是因为下面这行,每次对vehicle.js的请求在用户登录时都会导致用户反序列化?

var vehicle = require('./routes/vehicle')(passport);

避免这种不必要的反序列化的一种方法是将不需要身份验证的路由从vehicle.js 分离到不同的文件,并且不将该护照对象传递给该文件(因为它传递给vehicle.js in app.js)。我不知道这是否是解决此问题的正确方法。

【问题讨论】:

    标签: javascript node.js express passport.js passport-facebook


    【解决方案1】:

    如果你使用passport.session() 中间件,反序列化将发生在每条路由上: https://github.com/jaredhanson/passport/blob/33075756a626999c6e2efc872b055e45ae434053/lib/strategies/session.js#L53-L69

    解决方案是仅将其添加到使用护照的人中。

    【讨论】:

    • 你的意思是什么解决方案是只将它添加到使用护照的人
    【解决方案2】:

    您可以将护照中间件包装在一个自定义中间件中,该中间件只为您指定的路由调用它。所以而不是:

    app.use(passport.session());
    

    你可以:

    app.use(function(req, res, next){
      if(req.url.match('api/image'))
        next(); // do not invoke passport
      else
        passport.session()(req, res, next)
        // same as doing == app.use(passport.session())
    });
    

    【讨论】:

    • 正是我想要的,谢谢。不过,我有一个问题,如果没有弄错上面的 if 条件,则每个请求都执行。正确的?不知道如果条件的成本是多少。另外,您认为使用 if 条件或将 passport.session() 应用于特定路由(在分离安全/非安全路由之后)是否有效?
    • @Raf 添加中间件的成本几乎为零。 I'm measuring ~0.06ms。它的生产量可能会更少。所以对我来说,从效率方面来说,这并不重要。我可能会根据其他因素做出选择,例如更有意义的代码。
    • @Raf 除了提到的 laggingreflex 之外,我还调整了护照反序列化功能以存储“反序列化”用户值的临时(如 10-20 秒)内存副本。原因是很多时候用户快速浏览页面,或者一个页面可能有多个请求。在这种情况下,我会查找 mongodb 一次,然后在接下来的 20 秒左右,任何额外的请求都是从内存中处理的,而不是访问 mongodb/db-server。这让我的网页响应速度快了很多。
    • @user3658423 有什么办法可以查看护照反序列化功能的调整版本吗?您可以将其添加为答案,我一定会给您一个赞成票。
    猜你喜欢
    • 2015-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多