Saltar al contenidoPedro Farbo
Lección 13 / 2545 min

Autorización y RBAC

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! 🚀

¿Te gustó el contenido? ¡Tu contribución ayuda a mantener todo online y gratuito!

PIX:0737160d-e98f-4a65-8392-5dba70e7ff3e