Node Hero – Node.js Autenticación utilizando Passport.js

Este tutorial de Passport.js te guiará a través de los pasos para configurar una estrategia de autenticación Node.js local utilizando Redis. Aprenderás a crear una interfaz de autenticación con Passport.js, donde los usuarios proporcionarán sus nombres de usuario y contraseñas. A pesar de su complejidad, los mecanismos de autenticación se pueden implementar fácilmente en Node.js.

Tecnologías a utilizar

Antes de saltar de cabeza a nuestro tutorial de autenticación Passport.js, echemos un vistazo a las tecnologías que vamos a utilizar en este capítulo.

¿Qué es Passport.js?

  • Passport.js es un middleware de autenticación Node.js simple y discreto para Node.js
  • Passport.js se puede colocar en cualquier aplicación web basada en Express.js.
  • Passport es un middleware de autenticación para Node.js que vamos a utilizar para la administración de sesiones.

¿Qué es Redis?

Redis es un almacén de estructura de datos en memoria de código abierto (con licencia BSD), utilizado como base de datos, caché y intermediario de mensajes.

Redis está diseñado para admitir diferentes tipos de estructuras de datos abstractas, como cadenas, hashes, listas, conjuntos, conjuntos ordenados con consultas de rango, mapas de bits, hipervínculos e índices geoespaciales con consultas de radio.

Vamos a almacenar la información de la sesión de nuestro usuario en Redis, y no en la memoria del proceso. De esta manera nuestra aplicación será mucho más fácil de escalar.

La aplicación de demostración que necesita autenticación

Para propósitos de demostración, construyamos una aplicación que haga solo lo siguiente:

  • exponer un formulario de inicio de sesión,
  • exponer dos páginas protegidas:
    • una página de perfil,
    • notas aseguradas

La estructura del proyecto

Vamos a utilizar la siguiente estructura:


├── app
| ├── authentication
| ├── note
| ├── user
| ├── index.js
| └── layout.hbs
├── config
| └── index.js
├── index.js
└── package.json

Como puedes ver, organizaremos los archivos y directorios en torno a las características. Tendremos una página de usuario, una página de notas y algunas funciones relacionadas con la autenticación.

El flujo de autenticación Node.js

Nuestro objetivo es implementar el siguiente flujo de autenticación en nuestra aplicación utilizando Passport.js:

  1. El usuario ingresa nombre de usuario y contraseña
  2. La aplicación comprueba si coinciden.
  3. Si coinciden, envía un encabezado Set-Cookie que se utilizará para autenticar otras páginas.
  4. Cuando el usuario visita páginas del mismo dominio, la cookie configurada previamente se agregará a todas las solicitudes
  5. Autentica las páginas restringidas con esta cookie.

Para configurar una estrategia de autenticación como esta en una aplicación Node.js usando Passport.js, sigue estos tres pasos:

Paso 1: Configuración de Express

Vamos a utilizar Express para el marco del servidor.


// file:app/index.js
const express = require('express')
const passport = require('passport')
const session = require('express-session')
const RedisStore = require('connect-redis')(session)

const app = express()
app.use(session({
store: new RedisStore({
url: config.redisStore.url
}),
secret: config.redisStore.secret,
resave: false,
saveUninitialized: false
}))
app.use(passport.initialize())
app.use(passport.session())

¿Qué hicimos aquí?

En primer lugar, requerimos todas las dependencias que necesita la administración de la sesión. Después de eso, hemos creado una nueva instancia del módulo express-session, que almacenará nuestras sesiones.

Para la tienda de respaldo, estamos usando Redis, pero puedes usar cualquier otro, como MySQL o MongoDB.

Paso 2: Configuración de Passport.js para Node.js

Passport.js es un gran ejemplo de una biblioteca que usa complementos. En este tutorial de passport.js, estamos agregando el módulo passport-local que permite la integración fácil de una estrategia de autenticación local simple utilizando nombres de usuario y contraseñas.

En aras de la simplicidad, en este ejemplo, no estamos utilizando una segunda tienda de respaldo, sino solo una instancia de usuario en memoria. En aplicaciones de la vida real, findUser buscaría un usuario en una base de datos.


// file:app/authenticate/init.js
const passport = require('passport')
const bcrypt = require('bcrypt')
const LocalStrategy = require('passport-local').Strategy

const user = {
username: 'test-user',
passwordHash: 'bcrypt-hashed-password',
id: 1
}

passport.use(new LocalStrategy(
(username, password, done) => {
findUser(username, (err, user) => {
if (err) {
return done(err)
}

// Usuario no encontrado
if (!user) {
return done(null, false)
}

// Utiliza siempre contraseñas hash y comparaciones de tiempo fijo
bcrypt.compare(password, user.passwordHash, (err, isValid) => {
if (err) {
return done(err)
}
if (!isValid) {
return done(null, false)
}
return done(null, user)
})
})
}
))


Una vez que las devoluciones de findUser con nuestro objeto de usuario lo único que queda es comparar la contraseña de hash del usuario y la contraseña real para ver si hay una coincidencia. Siempre almacena las contraseñas con hash y usa la comparación de tiempo fijo para evitar ataques de tiempo.

Si es una coincidencia, permitimos que el usuario ingrese: return done(null, user) ( devolviendo al usuario el Passport ), si no devolvemos un error no autorizado (devolviendo nada al Passport- return done(null)).

Paso 3: Agregar puntos finales protegidos

Para agregar puntos finales protegidos, estamos aprovechando el patrón de middleware que utiliza Express. Para eso, vamos a crear el middleware de autenticación primero:


// file:app/authentication/middleware.js
function authenticationMiddleware () {
return function (req, res, next) {
if (req.isAuthenticated()) {
return next()
}
res.redirect('/')
}
}


Solo tiene un rol si el usuario está autenticado (tiene las cookies correctas); simplemente llama al siguiente middleware. De lo contrario, redirige a la página donde el usuario puede iniciar sesión.

Su uso es tan fácil como agregar un nuevo middleware a la definición de ruta.


// file:app/user/init.js
const passport = require('passport')

app.get('/profile', passport.authenticationMiddleware(), renderProfile)

Resumen – Autenticación con Passport.js

En este tutorial de Passport.js, has aprendido cómo agregar una autenticación básica a tu aplicación Node.js. Más adelante, puedes extenderlo con diferentes estrategias de autenticación, como Facebook o Twitter. Puede encontrar más estrategias en http://passportjs.org/.