Passport.js middleware паспорт.initialize () не используется

104

Я использую node с express + mongoose и пытаюсь использовать password.js с спокойным api.
Я продолжаю получать это исключение после успешной аутентификации (я вижу URL-адрес обратного вызова в браузере):

/Users/naorye/dev/naorye/myproj/node_modules/mongoose/lib/utils.js:419
        throw err;
              ^
Error: passport.initialize() middleware not in use
    at IncomingMessage.req.login.req.logIn (/Users/naorye/dev/naorye/myproj/node_modules/passport/lib/passport/http/request.js:30:30)
    at Context.module.exports.delegate.success (/Users/naorye/dev/naorye/myproj/node_modules/passport/lib/passport/middleware/authenticate.js:194:13)
    at Context.actions.success (/Users/naorye/dev/naorye/myproj/node_modules/passport/lib/passport/context/http/actions.js:21:25)
    at verified (/Users/naorye/dev/naorye/myproj/node_modules/passport-facebook/node_modules/passport-oauth/lib/passport-oauth/strategies/oauth2.js:133:18)
    at Promise.module.exports.passport.use.GitHubStrategy.clientID (/Users/naorye/dev/naorye/myproj/config/passport.js:91:24)
    at Promise.onResolve (/Users/naorye/dev/naorye/myproj/node_modules/mongoose/node_modules/mpromise/lib/promise.js:162:8)
    at Promise.EventEmitter.emit (events.js:96:17)
    at Promise.emit (/Users/naorye/dev/naorye/myproj/node_modules/mongoose/node_modules/mpromise/lib/promise.js:79:38)
    at Promise.fulfill (/Users/naorye/dev/naorye/myproj/node_modules/mongoose/node_modules/mpromise/lib/promise.js:92:20)
    at /Users/naorye/dev/naorye/myproj/node_modules/mongoose/lib/query.js:1822:13

Прочитал, что надо ставить app.use(passport.initialize());и app.use(passport.session());раньше app.use(app.router);и вот что сделал. Вот мой express.js, который регистрирует промежуточное ПО:

var express = require('express'),
    mongoStore = require('connect-mongo')(express),
    flash = require('connect-flash'),
    helpers = require('view-helpers');

module.exports = function (app, config, passport) {
    app.set('showStackError', true);
    // should be placed before express.static
    app.use(express.compress({
        filter: function (req, res) {
            return /json|text|javascript|css/.test(res.getHeader('Content-Type'));
        },
        level: 9
    }));
    app.use(express.favicon());
    app.use(express.static(config.root + '/public'));

    app.use(express.logger('dev'));

    // set views path, template engine and default layout
    app.set('views', config.root + '/app/views');
    app.set('view engine', 'jade');

    app.configure(function () {
        // use passport session
        app.use(passport.initialize());
        app.use(passport.session());

        // dynamic helpers
        app.use(helpers(config.app.name));

        // cookieParser should be above session
        app.use(express.cookieParser());

        // bodyParser should be above methodOverride
        app.use(express.bodyParser());
        app.use(express.methodOverride());

        // express/mongo session storage
        app.use(express.session({
            secret: 'linkit',
            store: new mongoStore({
                url: config.db,
                collection : 'sessions'
            })
        }));

        // connect flash for flash messages
        app.use(flash());

        // routes should be at the last
        app.use(app.router);

        // assume "not found" in the error msgs
        // is a 404. this is somewhat silly, but
        // valid, you can do whatever you like, set
        // properties, use instanceof etc.
        app.use(function(err, req, res, next){
            // treat as 404
            if (~err.message.indexOf('not found')) {
                return next();
            }

            // log it
            console.error(err.stack);

            // error page
            res.status(500).render('500', { error: err.stack });
        });

        // assume 404 since no middleware responded
        app.use(function(req, res, next){
            res.status(404).render('404', {
                url: req.originalUrl,
                error: 'Not found'
            });
        });
    });
};

Что случилось?

ОБНОВЛЕНИЕ Согласно @Peter Lyons, я изменил порядок конфигураций на следующий, но все равно получил ту же ошибку:

var express = require('express'),
    mongoStore = require('connect-mongo')(express),
    flash = require('connect-flash'),
    helpers = require('view-helpers');

module.exports = function (app, config, passport) {
    app.set('showStackError', true);
    // should be placed before express.static
    app.use(express.compress({
        filter: function (req, res) {
            return /json|text|javascript|css/.test(res.getHeader('Content-Type'));
        },
        level: 9
    }));
    app.use(express.favicon());
    app.use(express.static(config.root + '/public'));

    app.use(express.logger('dev'));

    // set views path, template engine and default layout
    app.set('views', config.root + '/app/views');
    app.set('view engine', 'jade');

    app.configure(function () {

        // dynamic helpers
        app.use(helpers(config.app.name));

        // cookieParser should be above session
        app.use(express.cookieParser());

        // bodyParser should be above methodOverride
        app.use(express.bodyParser());
        app.use(express.methodOverride());

        // express/mongo session storage
        app.use(express.session({
            secret: 'linkit',
            store: new mongoStore({
                url: config.db,
                collection : 'sessions'
            })
        }));

        // connect flash for flash messages
        app.use(flash());

        // use passport session
        app.use(passport.initialize());
        app.use(passport.session());

        // routes should be at the last
        app.use(app.router);

        // assume "not found" in the error msgs
        // is a 404. this is somewhat silly, but
        // valid, you can do whatever you like, set
        // properties, use instanceof etc.
        app.use(function(err, req, res, next){
            // treat as 404
            if (~err.message.indexOf('not found')) {
                return next();
            }

            // log it
            console.error(err.stack);

            // error page
            res.status(500).render('500', { error: err.stack });
        });

        // assume 404 since no middleware responded
        app.use(function(req, res, next){
            res.status(404).render('404', {
                url: req.originalUrl,
                error: 'Not found'
            });
        });
    });
};
Наор
источник
Версии Express 4.x не поддерживают некоторые методы. См github.com/strongloop/express/wiki/Migrating-from-3.x-to-4.x
miksiii

Ответы:

207

Следуйте примеру, чтобы избежать ада вышедшего из строя промежуточного программного обеспечения, в которое так легко войти. Прямо из документации. Обратите внимание на то, что у вас это не совсем так.

var app = express();
app.use(require('serve-static')(__dirname + '/../../public'));
app.use(require('cookie-parser')());
app.use(require('body-parser').urlencoded({ extended: true }));
app.use(require('express-session')({
  secret: 'keyboard cat',
  resave: true,
  saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());

Документы

  1. cookieParser
  2. сессия
  3. Паспорт. инициализация
  4. паспорт. сессия
  5. app.router

Вы

  1. Паспорт. инициализация
  2. паспорт. сессия
  3. cookieParser
  4. сессия
  5. app.router
Питер Лайонс
источник
Я изменил его на то, что вы предлагаете, но он по-прежнему вызывает эту ошибку. Я обновил свой вопрос новым файлом express.js /
Наор
7
Итак, код, который у вас здесь, не является кодом верхнего уровня. Ранее в вашей программе вы делаете любые вызовы app.get, app.postи т.д.? Это приведет к тому, что маршрутизатор будет добавлен в стек раньше, чем вы предполагаете. Покажите нам ВСЕ откровенный код, начиная с момента, когда вы вызываете express()функцию для получения вашего appобъекта. Это мое второе предположение.
Питер Лайонс
3
Я заметил, что app.use (app.router); вызывается после инициализации паспорта, но я вызываю: require ('./ config / routes') (app, паспорт, auth); перед звонком, чтобы выразить конфигурацию. Переключение между двумя строками решило проблему. Спасибо!
Наор
1
Это сработало для меня! Но почему промежуточное ПО должно быть в таком порядке?
Энтони К
3
По дизайну, поэтому вы можете рассчитывать на выполнение предварительных условий. Сессия не будет работать, если cookieParser еще не проанализировал файлы cookie.
Питер Лайонс
12

В моем случае (то же сообщение об ошибке) я вообще забыл добавить инициализацию паспорта:

app.configure(function () {
    ...
    app.use(passport.initialize());
    app.use(passport.session());
});

ОБНОВЛЕНИЕ: работает только до экспресс-версии 3, версия 4 больше не поддерживает app.configure ()

Маттиас М
источник
1
App.configure больше использовать нельзя. github.com/strongloop/express/wiki/… .. Им следует обновить документы паспорта. право?
jack blank
9

В моем случае ошибка была связана с тем , что я пытался обещать req.loginбез привязки thisк req, поэтому при вызове функции она не могла найти passportнастройки. Решение является обязательным req.login.bind(req)перед передачей, promisifyесли вы используете Node v8.

Цзяи Ху
источник
И эта «проблема с областью видимости» возникает, например, когда вы используете деструктуризацию аргументов, такую ​​как function({ login })передача reqпервого аргумента. Ваше решение сработало для меня, спасибо
Мануэль Ди Иорио
Ага, это как thisработает в Javascript. Если вы не вызываете функцию как объектный метод, тогда thisбудет undefined(или windowв браузере)
Цзяи Ху
Совет для тех, кто читает этот ответ и не понимает его ... если вы исследуете Function.prototype.call, Function.prototype.applyкак thisработает в Javascript и принципы, лежащие в основе прототипного наследования, вы продвинетесь до уровня Javascript Guru в процессе :)
Stijn de Witt
Ура, я надеялся, что это будет так просто, какutil.promisify(req.login.bind(req));
Джулиан Х. Лам
4

Мне также помогло размещение маршрутов ПОСЛЕ конфигурации файлов cookie :

// init Cookies:
app.use(
    cookieSession({
        maxAge: 30 * 24 * 60 * 60 * 1000,
        keys: [keys.cookieKey]
    })
);
app.use(passport.initialize());
app.use(passport.session());

// init routes
const authRoutes = require("./routes/authRoutes")(app);
Михал Доби Добжаньски
источник
Есть идеи, почему эти маршруты инициализации после настройки работают?
Ishu
Это устранило мою проблему. Я переместил все вызовы routes.use после всего, что связано с паспортом.
Ник Ван Брант,
2

Ответ Питера Лайона помог мне решить эту проблему, но я решил ее немного по-другому.

app.use(
  cookieSession({
    maxAge: 30 * 24 * 60 * 60 * 1000,
    keys: [keys.cookieKey],
  }),
);
app.use(passport.initialize());
app.use(passport.session());

Взгляните на мой репозиторий GitHub, чтобы увидеть весь код, а не только фрагмент кода здесь.

Исак Ла Флер
источник
1

В моем случае (такое же сообщение об ошибке) я разрабатывал собственную стратегию, и мне не нужно использовать сеанс . Я просто забыл добавить промежуточное ПО для session: falseмаршрута authenticate.

  app.post('/api/public/auth/google-token',
    passport.authenticate('google-token', {
      session: false
    }),
    function (req: any, res) {
      res.send("hello");
    }
  );
ruwan800
источник
0

Поместите app.use(passport.initialize())промежуточное ПО перед промежуточным ПО, app.routerи оно работает как шарм

Сай Киран Кавали
источник