passport.js passport.initialize () middleware não em uso

103

Estou usando o node com express + mongoose e tentando usar passport.js com api repousante.
Continuo recebendo essa exceção após o sucesso da autenticação (vejo o URL de retorno de chamada no navegador):

/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

Li que deveria colocar app.use(passport.initialize());e app.use(passport.session());antes app.use(app.router);e foi o que fiz. Aqui está meu express.js que registra os middlewares:

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'
            });
        });
    });
};

O que está errado?

ATUALIZAÇÃO De acordo com @Peter Lyons, mudei a ordem das configurações para o seguinte, mas ainda recebo o mesmo erro:

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'
            });
        });
    });
};
Naor
fonte
As versões Express 4.x não oferecem suporte a alguns métodos. Consulte github.com/strongloop/express/wiki/Migrating-from-3.x-to-4.x
miksiii

Respostas:

206

Siga o exemplo para evitar o inferno de middleware fora de ordem que o express torna tão fácil de entrar. Direto dos documentos. Observe como o seu não corresponde exatamente a isso.

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());

Docs

  1. cookieParser
  2. sessão
  3. passport.initialize
  4. passport.session
  5. app.router

Vocês

  1. passport.initialize
  2. passport.session
  3. cookieParser
  4. sessão
  5. app.router
Peter Lyons
fonte
Eu mudei para o que você sugere, mas ainda gera este erro. Atualizei minha pergunta com o novo arquivo express.js /
Naor
7
Portanto, o código que você tem aqui não é o seu código de nível superior. No início de seu programa que você está fazendo todas as chamadas para app.get, app.post, etc? Isso fará com que o roteador seja adicionado à pilha antes do esperado. Mostre-nos TODOS o código relevante, começando com quando você invoca a express()função para obter seu appobjeto. Esse é meu segundo palpite.
Peter Lyons
3
Percebi que app.use (app.router); é chamado após a inicialização do passaporte, mas eu chamo: require ('./ config / routes') (app, passport, auth); antes de ligar para expressar configurações. Alternar entre as duas linhas resolveu o problema. Obrigado!
Naor
1
Isso funcionou para mim! Mas por que o middleware tem que estar em ordem assim?
Anthony para
3
Por design, para que você possa contar com o cumprimento dos pré-requisitos. A sessão não funcionará se cookieParser ainda não tiver analisado os cookies.
Peter Lyons,
12

No meu caso (mesma mensagem de erro) esqueci de adicionar as inicializações do passaporte:

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

ATUALIZAÇÃO: Funcionando apenas até a versão expressa 3, a versão 4 não é mais compatível com app.configure ()

Matthias M
fonte
1
App.configure não pode mais ser usado. github.com/strongloop/express/wiki/… .. Eles devem atualizar os documentos do passaporte. certo?
jack blank
9

No meu caso o erro foi porque eu estava tentando promisify req.loginsem vincular thisa req, então quando a função foi chamada ela não conseguiu encontrar as passportconfigurações. A solução é vinculativa req.login.bind(req)antes de passá-la promisifyse você estiver usando o Node v8.

Jiayi Hu
fonte
E esse "problema de escopo" acontece, por exemplo, quando você usa argumentos de desestruturação, como function({ login })passar o reqcomo primeiro argumento. A sua solução funcionou para mim, obrigado
Manuel Di Iorio
Sim, é assim que thisfunciona em Javascript. Se você não chamar a função como método de objeto, thisserá undefined(ou windowno navegador)
Jiayi Hu
Dica para quem está lendo esta resposta e não a entende ... se você investigar Function.prototype.call, Function.prototype.applycomo thisfunciona em Javascript e os princípios por trás da herança prototípica, você irá promover ao nível de Javascript Guru no processo :)
Stijn de Witt
Saúde, eu esperava que fosse tão simples quantoutil.promisify(req.login.bind(req));
Julian H. Lam
4

O que também me ajudou foi colocar as rotas APÓS a configuração dos cookies :

// 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);
Michał Dobi Dobrzański
fonte
tem alguma idéia de por que as rotas do init após a configuração estão funcionando?
Ishu
Isso resolveu meu problema. Mudei todas as ligações de routes.use depois de qualquer coisa relacionada ao passaporte.
Nick Van Brunt
2

A resposta de Peter Lyons me ajudou a resolver, mas resolvi de uma maneira um pouco diferente.

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

Dê uma olhada em meu repositório GitHub para todo o código e não apenas o snippet de código aqui.

Isak La Fleur
fonte
1

No meu caso (mesma mensagem de erro), estou desenvolvendo uma estratégia customizada e não preciso usar sessão . Eu apenas esqueci de adicionar session: falseno meu authenticatemiddleware de rota .

  app.post('/api/public/auth/google-token',
    passport.authenticate('google-token', {
      session: false
    }),
    function (req: any, res) {
      res.send("hello");
    }
  );
ruwan800
fonte