Autenticación con JWT en JSON Server
Introducción
En este artículo te explico como crear un API Rest completa junto a faker.js para que puedas hacer tus pruebas sin muchas complicaciones.
Como ampliación me parece muy interesante añadir a nuestra API Rest seguridad, así que en este nuevo artículo vamos a usar JWT para agregar un sistema de autenticación por token.
Voy a dar por sentado que tanto json-server (imprescindible) como faker.js (opcional) está(n) instalado(s).
Ampliación JSON server
Quiero aprovechar para hacer una pequeña ampliación sobre algunas funciones avanzadas que ofrece json-server, porque en el artículo anterior solo probamos el CRUD.
Para no extenderme mucho voy añadir el código que genera los datos falsos y el indice con las funciones avanzadas que podemos hacer en JSON Server:
let faker = require('faker');
let generateData = () => {
let data = []
for (let id = 0; id < 1000; id++) {
data.push({
"id": id,
"address": faker.address.streetAddress(),
"latitude": faker.address.latitude(),
"longitude": faker.address.longitude(),
"first_name": faker.name.firstName()
});
}
return { "data": data }
}
module.exports = generateData
/*
------------------------
FILTER
[
{
"id": 4,
"address": "866 Mohr Light",
"latitude": "-55.7908",
"longitude": "170.3427",
"first_name": "Tyree"
}
]
CURL: http://localhost:3000/data?id=4
------------------------
------------------------
PAGINATE
[
{
"id": 10,
"address": "612 Fahey Locks",
"latitude": "57.2960",
"longitude": "-54.5350",
"first_name": "Antone"
},
{
"id": 11,
"address": "09094 Tillman Brooks",
"latitude": "69.1174",
"longitude": "-134.4193",
"first_name": "Tito"
},
{
"id": 12,
"address": "8161 Kelton Shoal",
"latitude": "86.5114",
"longitude": "65.8792",
"first_name": "Freda"
},
{
"id": 13,
"address": "21785 Jasmin Trail",
"latitude": "-33.6972",
"longitude": "16.9923",
"first_name": "Bettye"
},
{
"id": 14,
"address": "620 Abernathy Ports",
"latitude": "-9.2774",
"longitude": "-47.5246",
"first_name": "Braden"
},
{
"id": 15,
"address": "24260 Wilfred Parks",
"latitude": "54.5527",
"longitude": "111.0772",
"first_name": "Roselyn"
},
{
"id": 16,
"address": "2826 Oral Trafficway",
"latitude": "-61.6411",
"longitude": "-124.6945",
"first_name": "Maude"
},
{
"id": 17,
"address": "0318 Hessel Junction",
"latitude": "-87.0497",
"longitude": "147.6963",
"first_name": "Allison"
},
{
"id": 18,
"address": "93964 Darion Lights",
"latitude": "-82.7756",
"longitude": "176.7674",
"first_name": "Quincy"
},
{
"id": 19,
"address": "341 Akeem Way",
"latitude": "11.6085",
"longitude": "67.5816",
"first_name": "Theresa"
}
]
CURL: http://localhost:3000/data?_page=2
Por defecto son paginaciones de 10 en 10 registros
------------------------
------------------------
SORT
[
........
{
"id": 605,
"address": "688 Shanna Via",
"latitude": "55.7688",
"longitude": "168.6224",
"first_name": "Zoila"
}
]
CURL: http://localhost:3000/data?_sort=first_name&order=asc
------------------------
*/
Para obtener mas información puedes ir a la siguiente url
Añadiendo la autenticación JWT
Lo primero que tenemos que hacer es instalar el paquete jsonwebtoken
npm i jsonwebtoken –save
Una vez terminada la instalación crearemos un fichero que usaremos configurar nuestra API REST junto a JWT. En el siguiente enlace puedes acceder al repositorio.
No obstante voy añadir el código completo con una pequeña explicación.
servidor.js
// Añadimos los módulos necesarios
const FS = require('fs');
const bodyParser = require('body-parser');
const jsonServer = require('json-server');
const JWT = require('jsonwebtoken');
const middlewares = jsonServer.defaults()
// Servidor Express
const server = jsonServer.create();
// Enrutador Express
const router = jsonServer.router('./db.json');
// Creamos un JSON con los usuarios (03f996214fba4a1d05a68b18fece8e71 == MD5 Hash 'usuarios' )
const userdb = JSON.parse(FS.readFileSync('./03f996214fba4a1d05a68b18fece8e71.json', 'UTF-8'));
// Middlewares predeterminados (logger, static, cors y no-cache)
server.use(middlewares)
// Parseo del body
server.use(jsonServer.bodyParser);
// Configuración TOKEN y duración
const SECRET_KEY = 'zxcasdqwe098765';
const expiresIn = '1h';
// Crear un TOKEN desde un payload
createToken = (payload) => JWT.sign(payload, SECRET_KEY, { expiresIn });
// Verificar el TOKEN
verifyToken = (token) => JWT.verify(token, SECRET_KEY, (err, decode) => decode !== undefined ? decode : err);
// Comprobamos si el usuario existe en nuestra 'base de datos'
isAuthenticated = ({ email, password }) => userdb.users.findIndex(user => user.email === email && user.password === password) !== - 1;
// Creamos un ENDPOINT para comprobar si el usuario existe y poder crear y enviar un TOKEN
server.post('/auth/login', (req, res) => {
const { email, password } = req.body;
if (isAuthenticated({ email, password }) === false) {
const status = 401;
const message = 'Contraseña y/o password incorrectos';
res.status(status).json({ status, message })
console.log(message);
return;
}
const access_token = createToken({ email, password });
res.status(200).json({ access_token })
});
// Añadir un middleware Express que verifique si el encabezado de autorización.
// Luego verificara si el token es válido para todas las rutas, excepto la ruta anterior,
// ya que esta es la que usamos para iniciar sesión en los usuarios.
server.use(/^(?!\/auth).*$/, (req, res, next) => {
if (req.headers.authorization === undefined || req.headers.authorization.split(' ')[0] !== 'Bearer') {
const status = 401;
const message = 'Header con autorización incorrecta';
res.status(status).json({ status, message });
console.log(message);
return;
}
try {
verifyToken(req.headers.authorization.split(' ')[1]);
next();
} catch (err) {
const status = 401;
const message = 'Error: TOKEN de acceso no válido';
res.status(status).json({ status, message });
console.log(message);
}
})
server.use(router);
server.listen(3000, () => {
console.log('API REST FUNCIONANDO')
});
El fichero para la base de datos lo he generado con el siguiente script en NodeJS (db.js) :
let faker = require('faker');
let data = { data: [] };
for (let id = 0; id < 1000; id++) {
data.data.push({
"id": id,
"address": faker.address.streetAddress(),
"latitude": faker.address.latitude(),
"longitude": faker.address.longitude(),
"first_name": faker.name.firstName()
});
}
console.log(JSON.stringify(data));
Para generar nuestra base de datos usaremos el siguiente comando:
node db.js > db.json
Y para finalizar, la tabla de los usuarios es un fichero JSON con unos mínimos datos:
{
"users": [
{
"id": 1,
"name": "ivan",
"email": "ivan@dominio.com",
"password": "qwerty1234"
},
{
"id": 2,
"name": "rafael",
"email": "rafael@dominio.es",
"password": "asdfgh56789"
}
]
}
Cuando tengamos todo el proyecto preparado usaremos el siguiente comando para iniciar nuestro servidor:
node servidor.js
A continuación unas pruebas del funcionamiento de JWT:
Ahora con el usuario y la contraseña validos:


