Passport login y sesión persistente


Antecedentes

Tengo una aplicación MEDIA con capacidades CRUD completamente probada con postman. He estado tratando de persistir el inicio de sesión desde hace bastante tiempo sin suerte. He leído y probado lo siguiente

Pero solo he podido registrar e iniciar sesión con un usuario, no persistir en iniciar sesión con una sesión.

Mi aplicación

Aquí hay un enlace al repositorio completo de github (si está buscando los últimos cambios, consulte la rama develop)

Mi comprensión de Auth/Login

Aquí está mi comprensión del inicio de sesión de usuario con ejemplos de código de mi proyecto y captura de pantalla de los resultados de postman, así como los registros de la consola.

Configuración del pasaporte

I tenga la siguiente autorización.js file, it configs passport

var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;

module.exports = function(app, user){

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

  // passport config
  passport.use(new LocalStrategy(user.authenticate()));

  passport.serializeUser(function(user, done) {
    console.log('serializing user: ');
    console.log(user);
    done(null, user._id);
  });

  passport.deserializeUser(function(id, done) {
    user.findById(id, function(err, user) {
      console.log('no im not serial');
      done(err, user);
    });
  });
};

Esto se llama en el archivo del servidor como

//code before
var user    = require('./models/user.js');
var auth    = require('./modules/auth.js')(app, user);
// code after

Enrutamiento para el inicio de sesión

En mis rutas tengo la ruta de inicio de sesión de la siguiente manera

router.post('/login', function(req, res, next) {

  passport.authenticate('local', function(err, user, info) {

    if (err) {
        return next(err);
    }

    if (!user) {
        return res.status(401).json({
            err: info
        });
    }

    req.logIn(user, function(err) {

        if (err) {
            return res.status(500).json({
                err: 'Could not log in user'
            });
        }

        res.status(200).json({
            status: 'Login successful!'
        });

    });
  })(req, res, next);
});

Esta ruta funciona como se probó con postman. Introduzco los detalles ' joe ' y 'pass' y obtengo la siguiente respuesta.

introduzca la descripción de la imagen aquí

Cuando se golpea esta ruta también podemos ver en la consola que el usuario es serializa.

introduzca la descripción de la imagen aquí

Entonces, ¿qué sigue?

Aquí es donde me pierdo. Tengo algunas preguntas.

  1. ¿El usuario está ahora en una sesión en mi servidor?
  2. ¿Debo enviar el req.session.passport.user de vuelta al cliente?
  3. ¿Necesito el ID de sesión en todas las solicitudes futuras?

Probando la sesión

Tengo una segunda configuración de ruta para probar la sesión es la siguiente

router.get('/checkauth', passport.authenticate('local'), function(req, res){

    res.status(200).json({
        status: 'Login successful!'
    });

});

La parte passport.authenticate('local') (pensé) está allí para probar si el la sesión de usuario existe antes de dar acceso a la ruta, pero nunca obtengo una respuesta de 200 cuando corro esto, incluso después de iniciar sesión.

¿Esta ruta espera un req.session.passport.user pasado en el head o como argumento de datos en una solicitud http que requiere auth?

Si me perdí algo o estoy entendiendo algo mal, por favor dígame, cualquier entrada es apreciada. Gracias a todos.

Author: Joe Lloyd, 2016-04-07

5 answers

¿El usuario está ahora en una sesión en mi servidor?

No, necesita usar el middleware express-session antes de app.use(passport.session()); para almacenar realmente la sesión en memoria/base de datos. Este middleware se encarga de configurar las cookies en los navegadores y convierte las cookies enviadas por los navegadores en objeto req.session. PassportJS solo usa ese objeto para deserializar aún más al usuario.

Debería enviar el pedido.sesion.pasaporte.usuario volver al cliente?

Si su cliente espera un user recurso al iniciar sesión, entonces usted debe. De lo contrario, no veo ninguna razón para enviar el objeto user al cliente.

¿Necesito el ID de sesión en todas las solicitudes futuras?

Sí, para todas las solicitudes futuras, se requiere el id de sesión. Pero si tu cliente es un navegador, no necesitas enviar nada. El navegador almacenará el ID de sesión como cookie y lo enviará para todas las solicitudes posteriores hasta que caduque la cookie. express-session leerá esa cookie y adjuntará la correspondiente objeto de sesión como req.session.

Probando la sesión

passport.authenticate('local') es para autenticar credenciales de usuario desde el cuerpo del POST. Debe usar esto solo para la ruta de inicio de sesión.

Pero para comprobar si el usuario está autenticado en todas las demás rutas, puede comprobar si req.user está definido.

function isAuthenticated = function(req,res,next){
   if(req.user)
      return next();
   else
      return res.status(401).json({
        error: 'User not authenticated'
      })

}
router.get('/checkauth', isAuthenticated, function(req, res){

    res.status(200).json({
        status: 'Login successful!'
    });
});
 41
Author: hassansin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-10 09:20:40

Como dice @hassansin, debe usar un middleware que implemente la administración de sesiones. Pasaporte.el middleware session () es conectar el framework passport a la administración de sesiones y no implementar sesión por sí mismo. Puede utilizar el express-session middleware para implementar la gestión de sesiones. Necesitas modificar tu auth.js de la siguiente manera

var passport = require('passport');
var session = require('express-session');
var LocalStrategy = require('passport-local').Strategy;

module.exports = function(app, user){
  app.use(session({secret: 'some secret value, changeme'}));    

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

  // passport config
  passport.use(new LocalStrategy(user.authenticate()));

  passport.serializeUser(function(user, done) {
    console.log('serializing user: ');
    console.log(user);
    done(null, user._id);
  });

  passport.deserializeUser(function(id, done) {
    user.findById(id, function(err, user) {
      console.log('no im not serial');
      done(err, user);
    });
  });
};

Tenga en cuenta que en este caso el motor de sesión está utilizando el almacén de memoria y no funcionó si escala su aplicación y aplicar equilibrio de carga. Cuando se llega a este estado de desarrollo algo como el connect-redis será necesario almacenar sesión.

También tenga en cuenta que debe cambiar el valor secreto utilizado en la llamada de midleware de la sesión y usar el mismo valor en todas las instancias de la aplicación.

 8
Author: yeiniel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-14 16:53:48

Según la documentación del pasaporte , req.user se establecerá en el usuario autenticado. Sin embargo, para que esto funcione, necesitará el módulo express-session. No debería necesitar nada más que lo que ya tiene para que el pasaporte funcione.

En cuanto a probar la sesión, puede tener una función de middleware que comprueba si req.usuario está configurado, si lo está, sabemos que el usuario está autenticado, y si no lo está, puede redirigir al usuario.

Usted podría por ejemplo tener un middleware función que puede utilizar en cualquier ruta que desee autenticar.

Autenticado.js

module.exports = function (req, res, next) {
    // if user is authenticated in the session, carry on
    if (req.user) {
        next();
    }
    // if they aren't redirect them to the login page
    else {
        res.redirect('/login');
    }
};

Controlador

var authenticated = require('./authenticated');

router.get('/protectedpage', authenticated, function(req, res, next) {
    //Do something here
});
 1
Author: Michael Hamilton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-13 16:15:13

No conozco una forma de verificar todas las sesiones existentes, pero Passport se encarga de la emisión de ID de sesión. Trate de comprobar que usted tiene req.usuario en su punto final de prueba después de iniciar sesión

 0
Author: tcmoore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-08 20:24:53

Pasaporte.js no funciona bien ya que almacena la sesión en el servidor (mala y no escalable). No desea almacenar ningún dato de sesión en el servidor (manteniéndolo sin estado), ya que entonces puede escalar sus clústeres y manejar más solicitudes.

Si nos fijamos en el código en el Pasaporte.biblioteca js, no hay mucho.. Construirlo usted mismo puede ser más rápido y más eficiente.

Aquí está un tutorial que escribí sobre la conexión a Google de una manera mucho mejor.

 0
Author: Jack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-22 04:09:50