Adición de autenticación a Express con Passport

La autenticación de usuario es una de esas cosas en las que probablemente no piense demasiado, pero casi todos los sitios web o aplicaciones lo requieren. Si tuvieras...

Introducción

La autenticación de usuario es una de esas cosas en las que probablemente no piense demasiado, pero casi todos los sitios web o aplicaciones lo requieren. Si tuviera que implementar la autenticación usted mismo, ¿podría hacerlo? Bueno, no te preocupes, probablemente no tengas que hacerlo. Dado que esta funcionalidad es tan común, casi todos los lenguajes/marcos web con los que me he encontrado ya tienen una solución lista para usar, y para Node, puede usar el complemento Express Passport.

Como siempre, le recomiendo que confíe en los paquetes populares para cosas como esta, ya que probablemente ya hayan pasado por los dolores de cabeza de encontrar errores y vulnerabilidades dentro del código.

¿Qué es el pasaporte

El paquete Pasaporte es un middleware de autenticación modular y expandible para Node.js que agrega funcionalidad de autenticación a su aplicación Express. Cuando la mayoría de las personas piensan en la autenticación, piensan en la combinación tradicional de nombre de usuario y contraseña. Si bien esto sigue siendo muy popular, el uso de otros servicios para autenticar a un usuario a través de OAuth se ha convertido en otro método popular. Dado que Passport es un middleware muy extensible, le permite conectar más de 300 proveedores de autenticación diferentes como Facebook, Twitter, Google y más, la mayoría de los cuales usan el estándar OAuth.

Sin embargo, no todas las estrategias usan OAuth. También puede elegir entre basado en hash (pasar un hash a través de una cadena de consulta, datos POST o en los encabezados HTTP), [Tokens web JSON] (https://en.wikipedia.org/wiki/JSON_Web_Token), o incluso simplemente Autenticación básica HTTP (así: http://username:[correo electrónico protegido]/). Aunque algunas de estas estrategias pueden tomar diferentes parámetros, en gran medida serán los mismos, por lo que debería poder intercambiar estrategias fácilmente si es necesario.

Para realizar un seguimiento de las sesiones de un usuario conectado entre solicitudes después de la autenticación inicial, Passport guarda los datos de la sesión en una cookie, que crea y envía al usuario. Todo esto se maneja detrás de escena para usted para todas las estrategias.

Cómo usar Passport

Para usar Passport, deberá conectarlo a su aplicación Express como lo haría con cualquier otro software intermedio:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var express = require('express');
var passport = require('passport');

var app = express();

app.configure(function() {
    app.use(express.cookieParser());
    app.use(express.bodyParser());
    app.use(express.session({ secret: 'derpy' }));

    app.use(passport.initialize());
    app.use(passport.session());    // Required for persistent login sessions (optional, but recommended)
});

Tenga en cuenta que si decide habilitar las sesiones, debe usar express.session() antes de passport.session() para asegurarse de que la sesión de inicio de sesión del usuario se restablezca en el orden correcto.

En la mayoría de los casos, deseará habilitar las sesiones; de lo contrario, no se recordará al usuario entre solicitudes.

Una vez que haya inicializado Passport y configurado las sesiones, es hora de configurar su estrategia. Como dije antes, la mayoría son bastante similares en cuanto a configuración, así que echemos un vistazo a la estrategia más utilizada, LocalStrategy:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
var LocalStrategy = require('passport-local').Strategy;

// Express/Passport setup here...

passport.use(new LocalStrategy(
    {
        usernameField: 'email',
        passwordField: 'password'
    },
    function(email, password, done) {
        User.loadOne({ email: email }).then(function(user) {
            if (!user || !user.authenticate(password)) {
                return done(null, false, { message: 'Incorrect email or password.' });
            }

            done(null, user);
        });
    })
);

La parte User.loadOne... será específica para su aplicación (estoy usando camuflaje ODM aquí). La devolución de llamada le envía el nombre de usuario/correo electrónico y la contraseña del usuario, que en el caso de "Estrategia local" se recuperó de los datos del formulario enviado con campos de entrada denominados correo electrónico y contraseña.

El formulario HTML del que provienen estos datos podría verse así:

1
2
3
4
5
<form method="post" role="form">
    <input type="text" name="email"/>
    <input type="password" name="password"/>
    <button type="submit">Login</button>
</form>

Observe que los campos se denominan correo electrónico y contraseña como especificamos en la Estrategia local anterior.

Con este correo electrónico y contraseña extraídos de req por Passport, podemos buscar al usuario en nuestra base de datos y luego comparar la contraseña proporcionada con la que obtuvimos de la base de datos (no se preocupe, es un hachís salado de la contraseña). Devolver un objeto de usuario válido a la devolución de llamada done le dice a Passport que las credenciales eran válidas. De lo contrario, devolvemos falso y un mensaje de error.

Lo último que debe hacer es decirle a Passport cómo serializar y deserializar el objeto de usuario. Lo que esto significa es que Passport necesita que le diga cómo identificar de forma única a un usuario con solo una cadena, como una identificación o una dirección de correo electrónico.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// Express/Passport setup here...

// Passport strategy setup here...

passport.serializeUser(function(user, done) {
    done(null, user.id);
});

passport.deserializeUser(function(id, done) {
    User.loadOne({ _id: id }).then(function(user) {
        done(null, user);
    }).catch(function(err) {
        done(err, null);
    });
});

En la función serializeUser anterior, ya recuperamos los datos del usuario de la base de datos y necesitamos decirle a Passport qué información usar en la cookie para identificar de manera única al usuario, que en este caso es user.id.

Para deserializeUser, Passport obtuvo la cadena de cookies (el ID de usuario) y necesita convertirla en un objeto de usuario. Así que usamos el id para buscar al usuario en la base de datos. Lo que devuelve aquí se pasa en cada solicitud como req.user a la ruta.

Conclusión

La mayoría de las aplicaciones web y muchas aplicaciones nativas utilizan algún tipo de autenticación, por lo que le convendría dejar que Passport se encargue de todo el trabajo duro por usted. Todo lo que necesita hacer es decidir sobre una estrategia.

No es que necesite más motivación para usar Passport, pero tenga en cuenta que obtener la autenticación correcta es difícil, y dado que es el guardián de los datos confidenciales de sus usuarios, sería mejor que confiara en un paquete que Ha sido probado y probado exhaustivamente.

¿Qué piensas de Passport y cómo lo has usado en el pasado? ¡Cuéntanos en los comentarios!