passport.js passport.initialize () middleware no en uso

103

Estoy usando node con express + mongoose e intento usar passport.js con restful api.
Sigo recibiendo esta excepción después del éxito de la autenticación (veo la URL de devolución de llamada en el 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

He leído que debería poner app.use(passport.initialize());y app.use(passport.session());antes app.use(app.router);y esto es lo que hice. Aquí está mi express.js que registra los 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'
            });
        });
    });
};

¿Qué está mal?

ACTUALIZACIÓN De acuerdo con @Peter Lyons, he cambiado el orden de las configuraciones al siguiente, pero sigo teniendo el mismo error:

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
fuente
Las versiones Express 4.x no admiten algunos métodos. Ver github.com/strongloop/express/wiki/Migrating-from-3.x-to-4.x
miksiii

Respuestas:

206

Siga el ejemplo para evitar el infierno del middleware fuera de servicio que hace que Express sea tan fácil de ingresar. Directamente de los documentos. Tenga en cuenta que el suyo no coincide exactamente con esto.

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. sesión
  3. passport.initialize
  4. passport.session
  5. app.router

  1. passport.initialize
  2. passport.session
  3. cookieParser
  4. sesión
  5. app.router
Peter Lyons
fuente
Lo cambié a lo que sugieres, pero aún arroja este error. Actualicé mi pregunta con el nuevo archivo express.js /
Naor
7
Entonces, el código que tiene aquí no es su código de nivel superior. A principios de su programa estás haciendo ninguna llamada a app.get, app.post, etc? Esos harán que el enrutador se agregue a la pila antes de lo previsto. Muéstrenos TODO el código relevante comenzando con cuando invoca la express()función para obtener su appobjeto. Esa es mi segunda suposición.
Peter Lyons
3
He notado que app.use (app.router); se llama después de inicializar el pasaporte, pero llamo: require ('./ config / routes') (app, passport, auth); antes de llamar para expresar configuraciones. Cambiar entre ambas líneas resolvió el problema. ¡Gracias!
Naor
1
¡Esto funcionó para mí! Pero, ¿por qué el middleware tiene que estar en ese orden?
Anthony Hasta el
3
Por diseño para que pueda confiar en que se cumplan los requisitos previos. La sesión no funcionará si cookieParser aún no ha analizado las cookies.
Peter Lyons
12

En mi caso (mismo mensaje de error) me olvidé de agregar las inicializaciones del pasaporte:

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

ACTUALIZACIÓN: Solo funciona hasta Express versión 3, la versión 4 ya no es compatible con app.configure ()

Matthias M
fuente
1
App.configure ya no se puede utilizar. github.com/strongloop/express/wiki/… .. Deberían actualizar los documentos del pasaporte. ¿Derecha?
jack en blanco
9

En mi caso, el error se debió a que estaba tratando de prometer req.loginsin vincularme thisa req, por lo que cuando se llamó a la función no pudo encontrar la passportconfiguración. La solución es vinculante req.login.bind(req)antes de pasarla a promisifysi está utilizando Node v8.

Jiayi Hu
fuente
Y este "problema de alcance" ocurre, por ejemplo, cuando utiliza la desestructuración de argumentos como function({ login })pasar el reqprimer argumento. Su solución funcionó para mí, gracias
Manuel Di Iorio
Sí, así es como thisfunciona en Javascript. Si no llama a la función como método de objeto, thisserá undefined(o windowen el navegador)
Jiayi Hu
Consejo para cualquiera que lea esta respuesta y no la entienda ... si investiga Function.prototype.call, Function.prototype.applycómo thisfunciona en Javascript y los principios detrás de la herencia prototípica, ascenderá al nivel de Javascript Guru en el proceso :)
Stijn de Witt
Saludos, esperaba que fuera tan simple comoutil.promisify(req.login.bind(req));
Julian H. Lam
4

Lo que me ayudó también fue poner rutas DESPUÉS de la configuración de las 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
fuente
¿Tiene alguna idea de por qué funcionan las rutas de inicio después de la configuración?
Ishu
Esto solucionó mi problema. Moví todas las llamadas de route.use después de cualquier cosa relacionada con el pasaporte.
Nick Van Brunt
2

La respuesta de Peter Lyons me ayudó a resolverlo, pero lo resolví de una manera un poco diferente.

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

Eche un vistazo a mi repositorio de GitHub para ver todo el código y no solo el fragmento de código aquí.

Isak La Fleur
fuente
1

En mi caso (mismo mensaje de error), estaba desarrollando una estrategia personalizada y no necesito usar una sesión . Me olvidé de agregar session: falseen mi ruta authenticatemiddleware.

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