@@ -2,75 +2,28 @@ import {
22 Injectable ,
33 CanActivate ,
44 ExecutionContext ,
5- ForbiddenException ,
6- Logger ,
7- UnauthorizedException ,
85} from '@nestjs/common' ;
96import { Reflector } from '@nestjs/core' ;
10- import { Request } from 'express' ;
11- import { Role , ROLES_KEY } from '../decorators/roles.decorator' ;
7+ import { ROLES_KEY } from '../decorators/roles.decorator' ;
128
13- interface JwtUser {
14- id : string | number ;
15- email ?: string ;
16- role : Role ;
17- }
18-
19- /**
20- * #158 – RolesGuard
21- *
22- * Must be used together with an AuthGuard that populates `request.user`
23- * from a validated JWT. The guard:
24- *
25- * 1. Skips routes that have no @Roles() decorator (public by default).
26- * 2. Rejects unauthenticated requests with 401.
27- * 3. Rejects authenticated requests whose role is not in the allowed list with 403.
28- *
29- * Registration (choose one):
30- * - Globally: app.useGlobalGuards(new RolesGuard(reflector)) in main.ts
31- * - Per-module: providers: [RolesGuard] and add @UseGuards(JwtAuthGuard, RolesGuard)
32- */
339@Injectable ( )
3410export class RolesGuard implements CanActivate {
35- private readonly logger = new Logger ( RolesGuard . name ) ;
36-
37- constructor ( private readonly reflector : Reflector ) { }
11+ constructor ( private reflector : Reflector ) { }
3812
3913 canActivate ( context : ExecutionContext ) : boolean {
40- // Collect roles from the handler first, then fall back to the controller level
41- const requiredRoles = this . reflector . getAllAndOverride < Role [ ] > ( ROLES_KEY , [
14+ const requiredRoles = this . reflector . getAllAndOverride < string [ ] > ( ROLES_KEY , [
4215 context . getHandler ( ) ,
4316 context . getClass ( ) ,
4417 ] ) ;
45-
46- // No @Roles () decorator → route is unrestricted at the role level
4718 if ( ! requiredRoles || requiredRoles . length === 0 ) {
4819 return true ;
4920 }
50-
51- const request = context . switchToHttp ( ) . getRequest < Request & { user ?: JwtUser } > ( ) ;
21+ const request = context . switchToHttp ( ) . getRequest ( ) ;
5222 const user = request . user ;
53-
54- if ( ! user ) {
55- throw new UnauthorizedException (
56- 'Authentication is required to access this resource.' ,
57- ) ;
23+ if ( ! user || ! user . roles ) {
24+ return false ;
5825 }
59-
60- const hasRole = requiredRoles . includes ( user . role ) ;
61-
62- if ( ! hasRole ) {
63- this . logger . warn (
64- `Access denied: user ${ user . id } (role="${ user . role } ") attempted to access ` +
65- `[${ context . getClass ( ) . name } ::${ context . getHandler ( ) . name } ] ` +
66- `which requires role(s): [${ requiredRoles . join ( ', ' ) } ]` ,
67- ) ;
68- throw new ForbiddenException (
69- `You do not have permission to perform this action. ` +
70- `Required role(s): ${ requiredRoles . join ( ' or ' ) } .` ,
71- ) ;
72- }
73-
74- return true ;
26+ // Support multiple roles per endpoint
27+ return requiredRoles . some ( role => user . roles . includes ( role ) ) ;
7528 }
7629}
0 commit comments