0% encontró este documento útil (0 votos)
8 vistas37 páginas

09 API Usuarios

Este documento detalla la implementación de usuarios y roles en una API REST utilizando Node.js y MySQL, enfocándose en la autenticación y autorización mediante JWT. Se describen los pasos para crear una tabla de usuarios, registrar y autenticar usuarios, así como proteger rutas según los permisos asignados a los roles. Además, se incluye la configuración necesaria en el frontend para manejar el registro e inicio de sesión de usuarios.

Cargado por

Marco
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
8 vistas37 páginas

09 API Usuarios

Este documento detalla la implementación de usuarios y roles en una API REST utilizando Node.js y MySQL, enfocándose en la autenticación y autorización mediante JWT. Se describen los pasos para crear una tabla de usuarios, registrar y autenticar usuarios, así como proteger rutas según los permisos asignados a los roles. Además, se incluye la configuración necesaria en el frontend para manejar el registro e inicio de sesión de usuarios.

Cargado por

Marco
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 37

Programación Web

Programación del Lado del Servidor


Implementando Usuarios y Roles en la API REST

“Cada sitio web comienza con una simple


idea y unas líneas de código; lo demás es
imaginación y esfuerzo.”
Información del Docente

• Nombre: Prof. Marco Antonio Cabrera Rufino.

• Correo Electrónico: [email protected].

• Horario de Clases: Lunes, Miércoles y Viernes de 8:00 a 10:00 am.

• Horario de Consulta: (El docente lo agregará).


Introducción
Ahora agregaremos usuarios y roles a nuestra API REST para mejorar la seguridad y
restringir quién puede realizar ciertas acciones.

Lo que haremos:
• Crear la tabla de usuarios en MySQL.
• Registrar y autenticar usuarios con JWT.
• Asignar roles (admin, usuario).
• Proteger las rutas (GET, POST, PUT, DELETE) según los permisos.
• Probar la autenticación con Postman o en un frontend.
Instalar Librerías Necesarias
Ejecuta estos comandos en la terminal:

npm install bcryptjs jsonwebtoken mysql2 dotenv cors express

• bcryptjs: Cifra contraseñas antes de guardarlas.

• jsonwebtoken: Crea y verifica tokens JWT para autenticación.


Crear la Tabla de Usuarios en MySQL
Ejecuta estos comandos en MySQL para crear la tabla usuarios:

USE miDB;
CREATE TABLE usuarios (
id INT AUTO_INCREMENT PRIMARY KEY,
nombre VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
rol ENUM('admin', 'usuario') NOT NULL
DEFAULT 'usuario'
);

• Cada usuario tiene un email, password y un rol (admin o usuario).


• Los administradores pueden agregar, editar y eliminar productos.
Crear un Usuario Administrador en
MySQL Manualmente
Ejecuta estos comandos en MySQL para crear la tabla usuarios:

INSERT INTO usuarios (nombre, email, password, rol) VALUES ('Admin', '[email protected]',
'$2a$10$XwG/bF7JvM2tQOg4x9qgZe6a5HcvzJv8CTOvGf.5A3nri1d8lfGSi', 'admin');

Nota:
La contraseña aquí es "admin123", pero está cifrada con bcryptjs.
Configurar la Autenticación en Express
Añade estas rutas en server.js

require('dotenv').config();
const mysql = require('mysql2');
const express = require('express');
const cors = require('cors');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');

const app = express();


const PORT = 3000;

app.use(cors());
app.use(express.json());
Configurar la Autenticación en Express
Añade estas rutas en server.js
// Conectar a MySQL
const conexion = mysql.createConnection({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME
});

conexion.connect(error => {
if (error) {
console.error("Error de conexión a MySQL:", error);
return;
}
console.log("Conectado a MySQL");
});

// Clave secreta para los tokens JWT


const JWT_SECRET = process.env.JWT_SECRET || "supersecreto";
Registrar Usuarios (POST /register)
Añade esta ruta para registrar usuarios:

app.post('/register', async (req, res) => {


const { nombre, email, password, rol } = req.body;

// Verificar si el email ya está registrado


conexion.query('SELECT * FROM usuarios WHERE email = ?', [email], async (error, resultados) => {
if (resultados.length > 0) {
return res.status(400).json({ mensaje: "El correo ya está registrado" });
}

// Cifrar la contraseña
const hashedPassword = await bcrypt.hash(password, 10);
Registrar Usuarios (POST /register)
Añade esta ruta para registrar usuarios:

// Cifrar la contraseña
const hashedPassword = await bcrypt.hash(password, 10);

// Insertar el usuario en la base de datos


conexion.query('INSERT INTO usuarios (nombre, email, password, rol) VALUES (?, ?, ?, ?)',
[nombre, email, hashedPassword, rol || "usuario"],
(error, resultado) => {
if (error) throw error;
res.status(201).json({ mensaje: "Usuario registrado" });
}
);
});
});
Iniciar Sesión (POST /login)
Añade esta ruta para autenticar usuarios y generar un token:

app.post('/login', (req, res) => {


const { email, password } = req.body;

conexion.query('SELECT * FROM usuarios WHERE email = ?', [email], async (error, resultados) => {
if (resultados.length === 0) {
return res.status(401).json({ mensaje: "Usuario no encontrado" });
}

const usuario = resultados[0];


const passwordValida = await bcrypt.compare(password, usuario.password);

if (!passwordValida) {
return res.status(401).json({ mensaje: "Contraseña incorrecta" });
}
Iniciar Sesión (POST /login)
Añade esta ruta para autenticar usuarios y generar un token:

// Generar token JWT


const token = jwt.sign({ id: usuario.id, rol: usuario.rol }, JWT_SECRET, { expiresIn: "1h"
});

res.json({ mensaje: "Inicio de sesión exitoso", token });


});
});
Middleware para Proteger Rutas
Añade un middleware para validar JWT:

function verificarToken(req, res, next) {


const token = req.headers["authorization"];

if (!token) {
return res.status(403).json({ mensaje: "Token requerido" });
}

jwt.verify(token.split(" ")[1], JWT_SECRET, (error, decoded) => {


if (error) {
return res.status(401).json({ mensaje: "Token inválido" });
}
req.usuario = decoded;
next();
});
}
Middleware para Proteger Rutas
Añade un middleware para validar JWT:

function verificarToken(req, res, next) {


const token = req.headers["authorization"];

if (!token) {
return res.status(403).json({ mensaje: "Token requerido" });
}

jwt.verify(token.split(" ")[1], JWT_SECRET, (error, decoded) => {


if (error) {
return res.status(401).json({ mensaje: "Token inválido" });
}
req.usuario = decoded;
next();
});
}
Proteger Rutas con Permisos
Solo los administradores pueden agregar, editar o eliminar productos

// Obtener productos (Todos pueden ver)


app.get('/productos', verificarToken, (req, res) => {
conexion.query('SELECT * FROM productos', (error, resultados) => {
if (error) throw error;
res.json(resultados);
});
});
Proteger Rutas con Permisos
Solo los administradores pueden agregar, editar o eliminar productos

// Agregar producto (Solo admin)


app.post('/productos', verificarToken, (req, res) => {
if (req.usuario.rol !== "admin") {
return res.status(403).json({ mensaje: "No tienes permiso" });
}

const { nombre, precio } = req.body;


conexion.query('INSERT INTO productos (nombre, precio) VALUES (?, ?)', [nombre, precio], (error,
resultado) => {
if (error) throw error;
res.status(201).json({ id: resultado.insertId, nombre, precio });
});
});
Proteger Rutas con Permisos
Solo los administradores pueden agregar, editar o eliminar productos

// Editar producto (Solo admin)


app.put('/productos/:id', verificarToken, (req, res) => {
if (req.usuario.rol !== "admin") {
return res.status(403).json({ mensaje: "No tienes permiso" });
}

const { nombre, precio } = req.body;


conexion.query('UPDATE productos SET nombre = ?, precio = ? WHERE id = ?', [nombre, precio,
req.params.id], (error) => {
if (error) throw error;
res.json({ mensaje: "Producto actualizado" });
});
});
Proteger Rutas con Permisos
Solo los administradores pueden agregar, editar o eliminar productos

// Eliminar producto (Solo admin)


app.delete('/productos/:id', verificarToken, (req, res) => {
if (req.usuario.rol !== "admin") {
return res.status(403).json({ mensaje: "No tienes permiso" });
}

conexion.query('DELETE FROM productos WHERE id = ?', [req.params.id], (error) => {


if (error) throw error;
res.json({ mensaje: "Producto eliminado" });
});
});
Modificar index.html para Incluir
Registro e Inicio de Sesión
Abre tu index.html y agrega los siguientes formularios:

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Gestión de Productos</title>
</head>
<body>
<h1>Iniciar Sesión</h1>
<form id="loginForm">
<input type="email" id="email" placeholder="Correo electrónico" required>
<input type="password" id="password" placeholder="Contraseña" required>
<button type="submit">Ingresar</button>
</form>
Modificar index.html para Incluir
Registro e Inicio de Sesión
Abre tu index.html y agrega los siguientes formularios:

<h1>Registrar Usuario</h1>
<form id="registerForm">
<input type="text" id="nombre" placeholder="Nombre" required>
<input type="email" id="regEmail" placeholder="Correo electrónico" required>
<input type="password" id="regPassword" placeholder="Contraseña" required>
<select id="rol">
<option value="usuario">Usuario</option>
<option value="admin">Administrador</option>
</select>
<button type="submit">Registrar</button>
</form>
Modificar index.html para Incluir
Registro e Inicio de Sesión
Abre tu index.html y agrega los siguientes formularios:

<h1>Lista de Productos</h1>
<ul id="productos"></ul>

<script src="app.js"></script>
</body>
</html>
Modificar app.js para Manejar
Autenticación
Ahora en app.js, debemos hacer las peticiones al backend para login y registro.
document.addEventListener("DOMContentLoaded", () => {
const loginForm = document.getElementById("loginForm");
const registerForm = document.getElementById("registerForm");

// Iniciar sesión
loginForm.addEventListener("submit", async (e) => {
e.preventDefault();
const email = document.getElementById("email").value;
const password = document.getElementById("password").value;

const response = await fetch("http://localhost:3000/login", {


method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password }),
});
Modificar app.js para Manejar
Autenticación
Ahora en app.js, debemos hacer las peticiones al backend para login y registro.

const data = await response.json();

if (response.ok) {
localStorage.setItem("token", data.token);
alert("Inicio de sesión exitoso");
cargarProductos();
} else {
alert("Error: " + data.mensaje);
}
});
Modificar app.js para Manejar
Autenticación
Ahora en app.js, debemos hacer las peticiones al backend para login y registro.

// Registro de usuario
registerForm.addEventListener("submit", async (e) => {
e.preventDefault();
const nombre = document.getElementById("nombre").value;
const email = document.getElementById("regEmail").value;
const password = document.getElementById("regPassword").value;
const rol = document.getElementById("rol").value;

const response = await fetch("http://localhost:3000/register", {


method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ nombre, email, password, rol }),
});
Modificar app.js para Manejar
Autenticación
Ahora en app.js, debemos hacer las peticiones al backend para login y registro.

const data = await response.json();

if (response.ok) {
alert("Usuario registrado con éxito");
} else {
alert("Error: " + data.mensaje);
}
});
Modificar app.js para Manejar
Autenticación
Ahora//
enCargar
app.js, debemos hacer
productos las peticiones
desde la API al backend para login y registro.
async function cargarProductos() {
const token = localStorage.getItem("token");
const response = await fetch("http://localhost:3000/productos", {
headers: { "Authorization": `Bearer ${token}` },
});

const productos = await response.json();


const lista = document.getElementById("productos");
lista.innerHTML = "";

productos.forEach((producto) => {
let item = document.createElement("li");
item.textContent = `${producto.nombre} - $${producto.precio}`;
lista.appendChild(item);
});
}
});
JWT (JSON Web Token)
JWT (JSON Web Token) es un estándar de autenticación segura que permite verificar la
identidad de un usuario sin necesidad de guardar su sesión en el servidor. Se usa ampliamente
en APIs REST, autenticación de usuarios y autorización de accesos.

Ejemplo de uso: Cuando un usuario inicia sesión en una web, el servidor le envía un token JWT, y
cada vez que haga una petición a la API, enviará ese token para demostrar que está autenticado.
Estructura de un Token JWT
Cada parte tiene un propósito específico:

Parte Descripción Ejemplo Decodificado

Contiene el algoritmo de cifrado


Header { "alg": "HS256", "typ": "JWT" }
y el tipo de token

Contiene la información del


Payload usuario (id, rol, tiempo de { "id": "123", "rol": "admin", "iat": 1686224800 }
expiración, etc.)

Es una firma única generada con


XJZsGz5BLCy3kPaDkCmj6i9mzzhR8hQq4x-
Signature una clave secreta para evitar
YkmhtT_U
alteraciones del token
Estructura de un Token JWT
¿Cómo se usa JWT en la autenticación de usuarios?

El flujo de autenticación con JWT funciona así:


• El usuario inicia sesión → Envía su email y contraseña al servidor.
• El servidor valida las credenciales → Si son correctas, genera un token JWT y lo envía al
cliente.
• El cliente guarda el token → Normalmente en localStorage o sessionStorage.
• El cliente usa el token en cada petición a la API → Se envía en los headers.
• El servidor verifica el token en cada petición → Si es válido, responde con los datos
protegidos.
Estructura de un Token JWT
Cada parte tiene un propósito específico:
Implementación de JWT en server.js
Ejemplo de generación y verificación de un JWT en Node.js con jsonwebtoken:

const jwt = require('jsonwebtoken');


const JWT_SECRET = "supersecreto"; // Clave secreta
Este código hace lo siguiente:
app.post('/login', (req, res) => { • Si el usuario inicia sesión correctamente, genera
const { email, password } = req.body; un token JWT.
• El token tiene los datos del usuario (id y rol).
// Simulación de autenticación correcta • Expira en 1 hora (expiresIn: "1h").
if (email === "[email protected]" && password === "admin123") {
// Crear el token JWT con datos del usuario
const token = jwt.sign({ id: 1, rol: "admin" }, JWT_SECRET, { expiresIn: "1h" });
res.json({ mensaje: "Inicio de sesión exitoso", token });
} else {
res.status(401).json({ mensaje: "Credenciales incorrectas" });
}
});
Verificar un Token Antes de Acceder a
Rutas Protegidas
function verificarToken(req, res, next) {
const token = req.headers["authorization"];
if (!token) {
return res.status(403).json({ mensaje: "Token requerido" });
}

jwt.verify(token.split(" ")[1], JWT_SECRET, (error, decoded) => {


if (error) {
return res.status(401).json({ mensaje: "Token inválido" });
}
req.usuario = decoded; // Guarda los datos del usuario autenticado
next();
});
}
Explicación:
• Extrae el token JWT del encabezado HTTP.
• Usa jwt.verify() para verificar que el token no haya sido alterado.
• Si es válido, permite continuar con la solicitud.
¿Cómo Enviar un Token JWT desde el Cliente? (app.js)
loginForm.addEventListener("submit", async (e) => {
e.preventDefault();
const email = document.getElementById("email").value;
const password = document.getElementById("password").value;

const response = await fetch("http://localhost:3000/login", {


method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password }),
});
Cuando un usuario inicia sesión,
const data = await response.json(); guardamos el token en localStorage y lo
usamos en las peticiones.
if (response.ok) {
localStorage.setItem("token", data.token); // Guardar el token
alert("Inicio de sesión exitoso");
} else {
alert("Error: " + data.mensaje);
}
});
Para hacer peticiones autenticadas con
JWT:
async function cargarProductos() {
const token = localStorage.getItem("token");

const response = await fetch("http://localhost:3000/productos", {


headers: { "Authorization": `Bearer ${token}` },
});

const productos = await response.json();


console.log(productos);
}

Esto envía el token en cada petición al servidor para acceder


a rutas protegidas.
Actividad
Crear una mini aplicación de gestión de tareas, donde los estudiantes puedan:
• Ver una lista de tareas almacenadas en una base de datos MySQL.
• Agregar nuevas tareas desde el frontend usando un formulario.
• Eliminar tareas con un botón.

Instrucciones
Configurar la base de datos MySQL
• Crear una base de datos llamada gestor_tareas.
• Crear la tabla tareas con los siguientes campos:

CREATE TABLE tareas (


id INT AUTO_INCREMENT PRIMARY KEY,
descripcion VARCHAR(255) NOT NULL
);
Insertar algunas tareas de prueba:
INSERT INTO tareas (descripcion) VALUES ('Terminar informe'), ('Comprar suministros');
Actividad
Crear el backend con Node.js y Express (server.js)
• Incluir las rutas:
GET /tareas → Obtener todas las tareas.
• POST /tareas → Agregar una nueva tarea.
• DELETE /tareas/:id → Eliminar una tarea.
Crear el frontend (index.html)
• Mostrar la lista de tareas obtenida del backend.
• Incluir un formulario para agregar nuevas tareas.
• Incluir un botón de eliminar junto a cada tarea.
Conectar el frontend con el backend usando fetch()
• Hacer una petición GET al cargar la página para obtener las tareas.
• Enviar una petición POST al backend al agregar una tarea.
• Enviar una petición DELETE al eliminar una tarea.
Fin del tema

Gracias

También podría gustarte