En esta ocasión vamos a ver un ejemplo simple de código que muestra cómo configurar un servidor Node.js utilizando Express, autenticando la conexión con JWT.
¿Qué es Express?
Express es un framework de Node.js que proporciona una serie de características para el desarrollo de API, simplificando bastante el trabajo. Lo cual nos posibilitará, como veremos en este ejemplo, montar un CRUD completo.
El proyecto
Básicamente vamos a crear un sistema CRUD que nos permite conectar con una BD externa en MySQL, previo logueo del usuario. Si el login es correcto, se genera un token JWT que se usa para autenticar las diferentes rutas dle CRUD: GET, POST, PUT y DELETE.
Veremos el funcionamiento de las diferentes rutas usando Postman, para acceder a la API
Instalación y configuración
El primer requisito es tener instalado Node en el equipo. Una vez instalado, iniciamos un proyecto en la carpeta donde vamos a configurar nuestra aplicación
npm init -y
Una vez inicializado, instalaremos algunas librerias necesarias para el funcionamiento del proyecto.
Primero Express, para las rutas de la API
npm install express
Después una librería que nos permitirá conectar con MySQL
npm install mysql
Y finalmente la libreria que nos permitirá usar tokens JWT
npm install jsonwebtoken
Ahora ya tenemos configurado todo el ambiente necesario para empezar a trabajar.
Lo primero que haremos será configurar un fichero que nos permitirá conectar a la BD que tendremos creada. En el caso que nos ocupa, es una simple base de datos, con dos tablas, una con un usuario para el login y otra con datos para mostrar, nada más. El fichero exportará el modulo de conexión para poder usarlo más adelante.
// config_DB.js
const mysql = require('mysql');
const connection = mysql.createConnection({
host: 'localhost',
user: '_USUARIO_BD_',
password: '#_PASSWORD_DB_',
database: 'datos_bd_node'
});
connection.connect((err) => {
if (err) {
console.error('Error al conectar a la base de datos:', err);
return;
}
console.log('Conexión a la base de datos establecida');
});
module.exports = connection;
Ahora vamos a montar el fichero que nos permitirá autentificar el usuario y autorizar las rutas, si el token del login es correcto. También se exportan todos los parámetros, para poder usarlos más adelante en el servidor node.js.
// config_JWT.js
const jwt = require('jsonwebtoken');
const secretKey = 'CLAVE_JWT'; // Clave secreta para firmar los tokens JWT
// Middleware de autenticación JWT
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (token == null) return res.sendStatus(401); // No autorizado
jwt.verify(token, secretKey, (err, user) => {
if (err) return res.sendStatus(403); // Prohibido
req.user = user;
next(); // Continuar con la ejecución de la solicitud
});
}
module.exports = {
authenticateToken: authenticateToken,
jwt: jwt,
secretKey: secretKey
};
Ahora en nuestro fichero server.js (que controlará el servidor) importaremos express y los ficheros que hemos creado anteriormente
// Importa el módulo express y lo asigna a la constante express
const express = require('express');
// Inicializa una instancia de la aplicación express
const app = express();
// Define el puerto en el que se ejecutará el servidor, tomando el valor del entorno si está definido, de lo contrario utiliza el puerto 3000
const PORT = process.env.PORT || 3000;
// Importa la configuración de la conexión a la base de datos
const connection = require('./config_DB');
// Importa funciones y constantes relacionadas con la autenticación JWT
const { authenticateToken, jwt, secretKey } = require('./config_JWT');
// Middleware para parsear el cuerpo de las solicitudes POST como objetos JSON
app.use(express.json());
Ahora lo que resta es ir montando los diferentes metodos para las llamadas del CRUD.
Vemos el GET
// Ruta para leer y mostrar los datos de la tabla usuarios
// El middleware authenticateToken verifica si el token JWT en la solicitud es válido antes de permitir el acceso a esta ruta
app.get('/usuarios', authenticateToken, (req, res) => {
// Consulta todos los usuarios en la base de datos
connection.query('SELECT * FROM datos_usuarios', (error, results) => {
if (error) {
// En caso de error en la consulta, envía una respuesta de error al cliente
console.error('Error al realizar la consulta:', error);
return res.status(500).send('Error interno del servidor');
}
// Envia los resultados de la consulta como respuesta al cliente en formato JSON
res.json(results);
});
});
El GET:id
// Ruta para ver los datos de un usuario por su ID
// Esta ruta también utiliza el middleware authenticateToken para verificar la autenticación del usuario
app.get('/usuarios/:id_usuario', authenticateToken, (req, res) => {
// Obtiene el ID del usuario de los parámetros de la solicitud
const usuarioId = req.params.id_usuario;
// Consulta los datos del usuario con el ID proporcionado en la tabla usuarios
connection.query('SELECT * FROM datos_usuarios WHERE id_usuario = ?', usuarioId, (error, results) => {
if (error) {
console.error('Error al obtener los datos del usuario:', error);
return res.status(500).send('Error interno del servidor');
}
if (results.length === 0) {
// Si no se encuentran resultados, envía una respuesta de usuario no encontrado al cliente
return res.status(404).send('Usuario no encontrado');
}
// Envía los datos del usuario encontrado como respuesta al cliente en formato JSON
res.json(results[0]);
});
});
El POST
// Ruta para añadir un nuevo usuario a la tabla usuarios
// También utiliza el middleware authenticateToken para verificar la autenticación del usuario
app.post('/usuarios', authenticateToken, (req, res) => {
// Obtiene los datos del nuevo usuario del cuerpo de la solicitud
const nuevoUsuario = req.body;
// Inserta el nuevo usuario en la base de datos
connection.query('INSERT INTO datos_usuarios SET ?', nuevoUsuario, (error, results) => {
if (error) {
console.error('Error al insertar un nuevo usuario:', error);
return res.status(500).send('Error interno del servidor');
}
// Envía una respuesta de éxito al cliente
res.status(201).send('Usuario añadido correctamente');
});
});
El PUT
// Ruta para actualizar un usuario existente por su ID
// Utiliza el middleware authenticateToken para verificar la autenticación del usuario
app.put('/usuarios/:id_usuario', authenticateToken, (req, res) => {
// Obtiene el ID del usuario a actualizar de los parámetros de la solicitud
const usuarioId = req.params.id_usuario;
// Obtiene los datos actualizados del cuerpo de la solicitud
const datosActualizados = req.body;
// Actualiza los datos del usuario en la base de datos
connection.query('UPDATE datos_usuarios SET ? WHERE id_usuario = ?', [datosActualizados, usuarioId], (error, results) => {
if (error) {
console.error('Error al actualizar el usuario:', error);
return res.status(500).send('Error interno del servidor');
}
// Envía una respuesta de éxito al cliente
res.send('Usuario actualizado correctamente');
});
});
Y finalmente el metodo DELETE
// Ruta para borrar un usuario existente por su ID
// Utiliza el middleware authenticateToken para verificar la autenticación del usuario
app.delete('/usuarios/:id_usuario', authenticateToken, (req, res) => {
// Obtiene el ID del usuario a eliminar de los parámetros de la solicitud
const usuarioId = req.params.id_usuario;
// Elimina el usuario de la base de datos
connection.query('DELETE FROM datos_usuarios WHERE id_usuario = ?', usuarioId, (error, results) => {
if (error) {
console.error('Error al eliminar el usuario:', error);
return res.status(500).send('Error interno del servidor');
}
// Envía una respuesta de éxito al cliente
res.send('Usuario eliminado correctamente');
});
});
También incluimos en el código, el metodo para hacer el login y que nos tiene que devolver un token JWT si todo ha ido bien. El token, nos permitirá hacer las llamadas autenticadas al reto de funciones.
// Ruta para autenticar un usuario y generar un token JWT
app.post('/login', (req, res) => {
// Obtiene el nombre de usuario y la contraseña del cuerpo de la solicitud
const { username, password } = req.body;
// Verifica si el usuario existe en la base de datos y si la contraseña coincide
connection.query('SELECT * FROM user WHERE username = ? AND password = ?', [username, password], (error, results) => {
if (error) {
console.error('Error al buscar usuario:', error);
return res.status(500).send('Error interno del servidor');
}
if (results.length === 0) {
// Si no se encuentra el usuario o la contraseña es incorrecta, envía una respuesta de credenciales incorrectas
return res.status(401).json({ message: 'Credenciales incorrectas' });
}
// Si la autenticación es exitosa, genera un token JWT y lo envía al cliente como respuesta
const token = jwt.sign({ username: username }, secretKey);
res.json({ token: token });
});
});
Como siempre, os incluyo el enlace a mi repositorio de GitHub donde podréis encontrar este código.
También podréis encontrar más información sobre express y jsonwebtoken en las páginas de los respectivos proyectos.
Espero que os haya resultado útil este post.