/** * ROLES GUARD - REFERENCE IMPLEMENTATION * * @description Guard de autorización basado en roles (RBAC). * Verifica que el usuario tenga uno de los roles requeridos. * * @usage * ```typescript * @Get('admin') * @UseGuards(JwtAuthGuard, RolesGuard) * @Roles('admin', 'super_admin') * adminOnly(@Request() req) { * return { message: 'Admin data' }; * } * ``` * * @origin gamilit/apps/backend/src/modules/auth/guards/roles.guard.ts */ import { Injectable, CanActivate, ExecutionContext, ForbiddenException } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; /** * Metadata key para roles requeridos */ export const ROLES_KEY = 'roles'; @Injectable() export class RolesGuard implements CanActivate { constructor(private readonly reflector: Reflector) {} /** * Verificar si el usuario tiene los roles requeridos * * @description * 1. Obtiene los roles requeridos del decorador @Roles() * 2. Si no hay roles definidos, permite el acceso * 3. Compara el rol del usuario con los roles permitidos */ canActivate(context: ExecutionContext): boolean { // Obtener roles requeridos de handler y class const requiredRoles = this.reflector.getAllAndOverride(ROLES_KEY, [ context.getHandler(), context.getClass(), ]); // Si no hay roles definidos, permitir acceso if (!requiredRoles || requiredRoles.length === 0) { return true; } // Obtener usuario del request (inyectado por JwtAuthGuard) const { user } = context.switchToHttp().getRequest(); if (!user || !user.role) { throw new ForbiddenException('Usuario sin rol asignado'); } // Verificar si el usuario tiene alguno de los roles requeridos const hasRole = requiredRoles.includes(user.role); if (!hasRole) { throw new ForbiddenException( `Acceso denegado. Roles requeridos: ${requiredRoles.join(', ')}`, ); } return true; } } // ============ DECORADOR ROLES ============ import { SetMetadata } from '@nestjs/common'; /** * Decorador para definir roles requeridos en una ruta * * @param roles - Lista de roles que pueden acceder * * @usage * ```typescript * @Roles('admin', 'teacher') * @UseGuards(JwtAuthGuard, RolesGuard) * @Get('teachers') * getTeacherData() { ... } * ``` */ export const Roles = (...roles: string[]) => SetMetadata(ROLES_KEY, roles);