Structure: - control-plane/: Registries, SIMCO directives, CI/CD templates - projects/: Gamilit, ERP-Suite, Trading-Platform, Betting-Analytics - shared/: Libs catalog, knowledge-base Key features: - Centralized port, domain, database, and service registries - 23 SIMCO directives + 6 fundamental principles - NEXUS agent profiles with delegation rules - Validation scripts for workspace integrity - Dockerfiles for all services - Path aliases for quick reference 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
90 lines
2.4 KiB
TypeScript
90 lines
2.4 KiB
TypeScript
/**
|
|
* 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<string[]>(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);
|