Autenticación
La autenticación es el proceso mediante el cual se verifica la identidad de un usuario o sistema que intenta acceder a una aplicación o servicio. La idea es asegurarse de que quien está intentando acceder es realmente quien dice ser.
La idea ya la conocemos: nos logueamos con un usuario y contraseña, y el sistema nos permite acceder a ciertos recursos o funcionalidades que pertenecen a nuestor perfil dentro del sistema
¿Para qué sirve?
- Proteger recursos y datos sensibles.
- Controlar el acceso a funcionalidades específicas.
- Mejorar la seguridad general de la aplicación.
Implementación en express
Vamos a empezar con la parte facil, que es la creación de usuarios. Para esto vamos a necesitar la librería bcrypt, que nos permite hashear las contraseñas antes de guardarlas en la base de datos. El resto del proceso, es similar al que ya conocíamos para crear cualquier otro recurso.
- Instalación de dependencias
npm install bcrypt
- Migración de Prisma
model User {
id Int @id @default(uuid())
email String @unique
password String
name String
createdAt DateTime @default(now())
}
npx prisma migrate dev --name users
- Creación de usuarios
// /routes/auth.routes.js
import bcrypt from 'bcrypt';
import { Router } from "express";
import prisma from "../lib/prisma.js";
const router = Router();
router.post('/register', async (req, res) => {
const { email, password, name } = req.body;
const hashedPassword = await bcrypt.hash(password, 10); // El 10 es el número de rondas de salt
// Validar si el email ya está en uso
const isEmailTaken = await prisma.user.findUnique({
where: { email },
});
if (isEmailTaken) {
return res.status(400).json({ error: 'Email ya utilizado' });
}
const newUser = await prisma.user.create({
data: { email, password: hashedPassword, name },
});
return res.status(201).json({ message: 'Usuario creado', userId: newUser.id });
})
export default router;
- Integración en app.js
import express from 'express';
import authRoutes from './routes/auth.routes.js';
const app = express();
app.use(express.json());
app.use('/auth', authRoutes); // La ruta quedaría POST /auth/register
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Mi aplicacion esta funcionando en http://localhost:${port}`);
})
¿Cómo funciona la autenticación?
Existen varias formas de verificar la identidad de un usuario, pero una de las más comunes es mediante el uso de tokens JWT (JSON Web Tokens). Estos tokens permiten que el servidor verifique la identidad del usuario sin necesidad de almacenar su información en cada solicitud.
Proceso de autenticación con JWT
- Login: El usuario envía sus credenciales (email y contraseña) al servidor.
- Verificación: El servidor verifica las credenciales. Si son correctas, genera un token JWT que contiene información del usuario y una firma para garantizar su integridad.
- Envío del token: El servidor envía el token al cliente.
- Acceso a recursos protegidos: El cliente incluye el token en las solicitudes a recursos protegidos. El servidor verifica el token y, si es válido, permite el acceso.
Para el login y la generación de tokens, vamos a necesitar una librería adicional llamada jsonwebtoken. Esta nos permitirá crear y verificar tokens JWT.
npm install jsonwebtoken
Vamos a implementar el login y la generación del token:
// /routes/auth.routes.js
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import { Router } from "express";
import prisma from "../lib/prisma.js";
const router = Router();
router.post('/register', async (req, res) => {
const { email, password, name } = req.body;
const hashedPassword = await bcrypt.hash(password, 10); // El 10 es el número de rondas de salt
// Validar si el email ya está en uso
const isEmailTaken = await prisma.user.findUnique({
where: { email },
});
if (isEmailTaken) {
return res.status(400).json({ error: 'Email ya utilizado' });
}
const newUser = await prisma.user.create({
data: { email, password: hashedPassword, name },
});
return res.status(201).json({ message: 'Usuario creado', userId: newUser.id });
})
router.post('/login', async (req, res) => {
const { email, password } = req.body;
// Buscar al usuario por email
const user = await prisma.user.findUnique({
where: { email },
});
if (!user) {
return res.status(401).json({ error: 'Credenciales inválidas' });
}
// Verificar la contraseña
const isPasswordValid = await bcrypt.compare(password, user.password);
if (!isPasswordValid) {
return res.status(401).json({ error: 'Credenciales inválidas' });
}
// Generar el token JWT
const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { expiresIn: '1h' });
return res.status(200).json({ message: 'Login exitoso', token });
})
export default router;
Middleware de Autenticación
Vamos a crear un middleware que verifique la autenticación de los usuarios.
// /middlewares/auth.middleware.js
import jwt from 'jsonwebtoken';
const verifyToken = (req, res, next) => {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ error: 'Acceso no autorizado' });
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.userId = decoded.userId; // Guardamos el userId en la request para usarlo en las rutas
next();
} catch (error) {
return res.status(401).json({ error: 'Token inválido' });
}
};
export default verifyToken;
Para usar este middleware, simplemente lo importamos y lo aplicamos a las rutas que queremos proteger:
// routes/tareas.routes.js
import { Router } from "express";
import prisma from "../lib/prisma.js";
import verifyToken from "../middlewares/auth.middleware.js";
const router = Router();
router.get("/", async (req, res) => { // Cualquiera puede ver las tareas
const tareas = await prisma.tarea.findMany();
res.json(tareas);
});
router.post("/", verifyToken, async (req, res) => { // Solo los usuarios autenticados que pasen el middleware pueden crear tareas
const { titulo, descripcion, path } = req.body;
const tarea = await prisma.tarea.create({
data: {
titulo,
descripcion,
path,
},
});
res.json(tarea);
})
// ...
export default router;