Autorización RBAC
Role-Based Access Control para controlar permisos.
Middleware de Autorización
typescript
// src/middlewares/authorize.middleware.tsimport { Request, Response, NextFunction } from 'express';import { AppError } from '../errors/AppError'; type Role = 'USER' | 'ADMIN'; export const authorize = (...allowedRoles: Role[]) => { return (req: Request, res: Response, next: NextFunction) => { if (!req.user) { throw new AppError('No autenticado', 401); } if (!allowedRoles.includes(req.user.role as Role)) { throw new AppError('No tienes permiso para esta acción', 403); } next(); };};Uso en Rutas
typescript
// src/routes/product.routes.tsimport { authenticate } from '../middlewares/auth.middleware';import { authorize } from '../middlewares/authorize.middleware'; const router = Router(); // Públicorouter.get('/', controller.index);router.get('/:id', controller.show); // Solo adminrouter.post('/', authenticate, authorize('ADMIN'), validate(createProductSchema), controller.store); router.put('/:id', authenticate, authorize('ADMIN'), validate(updateProductSchema), controller.update); router.delete('/:id', authenticate, authorize('ADMIN'), controller.destroy);Middleware de Recurso Propio
typescript
// src/middlewares/own-resource.middleware.tsexport const ownResource = ( paramField: string = 'id', allowAdmin: boolean = true) => { return async (req: Request, res: Response, next: NextFunction) => { const resourceUserId = req.params[paramField]; // Admin puede acceder a todo if (allowAdmin && req.user?.role === 'ADMIN') { return next(); } // Usuario solo puede acceder a su propio recurso if (req.user?.id !== resourceUserId) { throw new AppError('No tienes permiso', 403); } next(); };}; // Usorouter.get('/users/:id/orders', authenticate, ownResource('id'), orderController.getUserOrders);Verificación en Service
typescript
// src/services/order.service.tsasync findUserOrders(userId: string, requestingUser: AuthUser) { // Usuario normal solo ve sus propios pedidos if (requestingUser.role !== 'ADMIN' && requestingUser.id !== userId) { throw new AppError('Acceso denegado', 403); } return prisma.order.findMany({ where: { userId }, include: { items: { include: { product: true } }, }, orderBy: { createdAt: 'desc' }, });}Permisos Granulares
typescript
// src/config/permissions.tsexport const permissions = { ADMIN: ['*'], USER: [ 'product:read', 'order:create', 'order:read:own', 'review:create', 'review:update:own', ],}; // Middleware de permiso específicoexport const hasPermission = (permission: string) => { return (req: Request, res: Response, next: NextFunction) => { const userRole = req.user?.role; const userPermissions = permissions[userRole]; if (userPermissions.includes('*') || userPermissions.includes(permission)) { return next(); } throw new AppError('Permiso denegado', 403); };};Resumen
- ✅ RBAC básico con roles
- ✅ Middleware de autorización
- ✅ Verificación de recurso propio
- ✅ Permisos granulares
Próxima clase: Subida de Archivos! 🚀