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
- pasaporte docs
- blog de toon io sobre login
- Sesión exprés
- Scotch io, node auth made easy
- Además de un montón de otros materiales de lectura ligera (Un montón de preguntas)
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.
Cuando se golpea esta ruta también podemos ver en la consola que el usuario es serializa.
Entonces, ¿qué sigue?
Aquí es donde me pierdo. Tengo algunas preguntas.
- ¿El usuario está ahora en una sesión en mi servidor?
- ¿Debo enviar el
req.session.passport.user
de vuelta al cliente? - ¿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.
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!'
});
});
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.
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
});
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
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.
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