PassportJS 中间件被多次调用

Posted

技术标签:

【中文标题】PassportJS 中间件被多次调用【英文标题】:PassportJS middleware being called multiple times 【发布时间】:2013-07-04 02:43:39 【问题描述】:

似乎每当我调用 Passport 的 ensureAuthenticated 中间件时,它都会导致 passport.deserializeUser 函数被向上调用 6-7 次。我不确定这是我的应用程序通过 Express、Sequelize 的结构还是 Passport 的导入方式。出于这个原因,我将列出一些文件,希望能找到它误入歧途的地方。

这就是我的所有结构

application/
  auth/
  models/
  node-modules/
  public/
  routes/
  views/
  app.js

我的假设是因为中间件不是单例,和/或因为我的路由设置很奇怪。 注意:我按照this 指南设置了单例续集方法。

./app.js

// .. imports

app.set('models', require('./models')); // singleton ORM (my assumption)
// .. session stuff
app.use(passport.initialize());
app.use(passport.session());
app.use(require('./auth'));
// .. etc

app.use('/', require('./routes')); // routing style possible issue?

// .. create server

./auth/index.js

module.exports = function () 

    var express   = require('express')
      , passport  = require('passport')
      , Local     = require('passport-local').Strategy
      , app       = express();


    passport.use(new Local(
        function(username, password, done) 
            app.get('models').User.find(
                where: 
                    username: username,
                    password: password
                
            ).done(function (err, user) 
                if (err) 
                    return done(err);
                
                if (!user) 
                    return done(null, false,  message: 'Invalid login' );
                
                return done(null, user);
            );
        
    ));

    passport.serializeUser(function(user, done) 
        done(null, user.id);
    );

    passport.deserializeUser(function(id, done) 
        app.get('models').User.find(id).done(function(err, user) 
            done(err, user);
        );
    );


    return app;
();

./auth/middleware.js

exports.check = function(req, res, next) 
    if (req.isAuthenticated()) 
        return next();
    
    res.redirect('/login')
;

exports.is = function(role) 
    return function (req, res, next) 
        if (req.usertypes[req.user.type] === role) next();
        else res.redirect('back');
    
;

./routes/index.js

module.exports = function () 

    var express  = require('express')
      , app      = express();


    app.get('/', function (req, res) 
        if (!req.user) res.redirect('/login');
        else res.redirect('/' + req.usertypes[req.user.type]);
    );

    app.use('/admin',    require('./admin'));
    app.use('/another1', require('./another1')); // yadda
    app.use('/another2', require('./another2')); // yadda
    app.use('/login',    require('./login'));

    app.get('/logout', function(req, res)
        req.logout();
        res.redirect('/');
    );


    return app;
();

最后./routes/admin.js

module.exports = function () 

    var express = require('express')
      , auth    = require('../auth/middleware')
      , admin   = express();


    // auth.check seems to be what's firing the multiple queries:
    // Executing: SELECT * FROM `users` WHERE `users`.`id`=1 LIMIT 1;
    // 6 times from the looks of it.

    admin.get('/', auth.check, auth.is('admin'), function (req, res) 
        res.render('admin', 
            username: 'req.user.username'
        );
    );

    admin.get('/users.json', auth.check, auth.is('admin'), function (req, res) 
        res.contentType('application/json');
        admin.get('models').User.findAll().done(function (err, users) 
            if (users.length === 0) 
                // handle
             else 
                res.send(JSON.stringify(users));
            
        );
    );

    admin.post('/adduser', auth.check, auth.is('admin'), function (req, res) 
        var post = req.body;
        admin.get('models').User.create(post).done(function (err, user) 
            if (!err) 
                res.send(JSON.stringify(success: true, users: user));
             else 
                res.send(JSON.stringify(success: false, message: err));
            
        );
    );


    return admin;
();

我知道这是一些代码,但我感觉它是非常非常简单的东西。任何指导将不胜感激。

【问题讨论】:

您使用的是什么编辑器/IDE?我强烈推荐使用 Jetbrains Webstorm。您只需添加几个断点并检查调用堆栈即可快速回答您的问题。 或者,或者,从deserializeUser 致电console.trace() 来自deserializeUser./auth/index.js 的日志/跟踪与SQL 执行重复——这似乎是被多次调用的内容。另外,只需 vim/zsh。 确保您的公用文件夹不是通过 express 调用,而是在它前面的某个东西(apache、nginx 等)调用。由于每个 CSS/JS/img/etc.调用也会触发中间件(发生在我身上)。 @user766987 我刚刚遇到了这个问题。所有静态资产都通过中间件运行的原因是因为您要么没有定义什么是静态资产,要么定义得太晚了。我必须告诉它使用/assets 作为公共文件的基础,然后你必须确保它出现在你的其他app.use 定义之前。 app.use('/assets', express.static(path.join(__dirname, 'public'))); 【参考方案1】:

这是因为您使用的 passportJS 会话中间件早于静态文件。因此,您的所有静态文件调用(如<img src="...">)通过会话中间件并调用deserializeUser()

解决方案

app.js 文件中使用您的会话中间件 app.use(express.static(...))

查看 jaredhandson 的这个 GitHub 问题答案以获取更多详细信息:https://github.com/jaredhanson/passport/issues/14#issuecomment-4863459

【讨论】:

【参考方案2】:

我刚刚遇到了这个问题。所有静态资产都通过中间件运行的原因是因为您要么没有定义什么是静态资产,要么定义得太晚了。我必须告诉它使用 /assets 作为公共文件的基础,然后你必须确保它出现在你的其他 app.use 定义之前。

app.use('/assets', express.static(path.join(__dirname, 'public')));

【讨论】:

以上是关于PassportJS 中间件被多次调用的主要内容,如果未能解决你的问题,请参考以下文章

身份验证后使用 passportjs-google 重定向到原始页面(无会话)

Express Passportjs在路由器回调中未进行身份验证

同时使用 JWT 和 Passportjs

护照中间件不运行

passportJS - passport-facebook 无法获取失败重定向路由

快速中间件调用多次