Files
app-padel/backend/src/middleware/auth.ts
Ivan Alcaraz b558372810 FASE 1 COMPLETADA: Fundamentos y Core del Backend
- API REST completa con Node.js + Express + TypeScript
- Autenticación JWT con roles (Player/Admin)
- CRUD completo de canchas
- Sistema de reservas con validaciones
- Base de datos SQLite con Prisma ORM
- Notificaciones por email (Nodemailer)
- Seed de datos de prueba
- Documentación de arquitectura

Endpoints implementados:
- Auth: register, login, refresh, me
- Courts: CRUD + disponibilidad
- Bookings: CRUD + confirmación/cancelación

Credenciales de prueba:
- admin@padel.com / admin123
- user@padel.com / user123
2026-01-31 08:11:53 +00:00

94 lines
2.2 KiB
TypeScript

import { Request, Response, NextFunction } from 'express';
import { verifyAccessToken, TokenPayload } from '../utils/jwt';
import prisma from '../config/database';
// Extender el tipo Request de Express para incluir usuario
declare global {
namespace Express {
interface Request {
user?: TokenPayload & { id: string };
}
}
}
// Middleware de autenticación
export const authenticate = async (
req: Request,
res: Response,
next: NextFunction
) => {
try {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return res.status(401).json({
success: false,
message: 'Token de autenticación no proporcionado',
});
}
const token = authHeader.substring(7);
if (!token) {
return res.status(401).json({
success: false,
message: 'Token no válido',
});
}
// Verificar token
const decoded = verifyAccessToken(token);
// Verificar que el usuario existe y está activo
const user = await prisma.user.findUnique({
where: { id: decoded.userId },
select: { id: true, isActive: true },
});
if (!user) {
return res.status(401).json({
success: false,
message: 'Usuario no encontrado',
});
}
if (!user.isActive) {
return res.status(401).json({
success: false,
message: 'Usuario desactivado',
});
}
// Añadir usuario al request
req.user = { ...decoded, id: user.id };
next();
} catch (error) {
return res.status(401).json({
success: false,
message: 'Token inválido o expirado',
});
}
};
// Middleware de autorización por roles
export const authorize = (...roles: string[]) => {
return (req: Request, res: Response, next: NextFunction) => {
if (!req.user) {
return res.status(401).json({
success: false,
message: 'No autenticado',
});
}
if (!roles.includes(req.user.role)) {
return res.status(403).json({
success: false,
message: 'No tienes permisos para realizar esta acción',
});
}
next();
};
};