Search code examples
angulartypescriptnestjsrolesguard

How to add multiple Nestjs RoleGuards in controllers


I have role guard for ADMIN, SUPERADMIN, USER, MODERATORS,

This is an example of one of the guards. An Admin guard in the case. They are working as I expected but I can't add multiple guards in the controller

import { Injectable, CanActivate, ExecutionContext, HttpException, HttpStatus } from '@nestjs/common';

@/Injectable()
export class AdminGuard implements CanActivate {
 constructor() { }

 canActivate(context: ExecutionContext) {
 const request = context.switchToHttp().getRequest();
 const user = request.user;

 if (user.usertype == 'Admin') {
 return true;
        }
 throw new HttpException('Unauthorized access', HttpStatus.BAD_REQUEST);
    }
}

in my controllers, I have this decorator

 
@UseGuards(AuthGuard('jwt'), AdminGuard)

I want to be able to do something like this

@UseGuards(AuthGuard('jwt'), AdminGuard, SuperAdminGuard)

or

@UseGuards(AuthGuard('jwt'), [AdminGuard, SuperAdminGuard, UserGuard])

or


@UseGuards(AuthGuard('jwt'), AdminGuard || SuperAdminGuard || UserGuard])

None of the above implementations worked. Is there a better way to go about it? Maybe there is something I am not doing right. I have checked the docs but I can't seem to make it work


Solution

  • I suggest to create one generic RolesGuard and define the required roles per controller or route handler with custom metadata:

    @Injectable()
    export class RolesGuard implements CanActivate {
      constructor(private readonly reflector: Reflector) {}
    
      canActivate(context: ExecutionContext): boolean {
        const roles = this.reflector.get<string[]>('roles', context.getHandler());
        if (!roles) {
          return true;
        }
        const request = context.switchToHttp().getRequest();
        const userType = request.user.userType;
        return roles.some(r => r === userType);
    
      }
    }
    

    Custom decorator to set the required roles:

    export const Roles = (...roles: string[]) => SetMetadata('roles', roles);
    

    How to use it?

    Now you can define the required roles as follows:

    // For this route you need either Superadmin or Admin privileges
    @Roles('Superadmin', 'Admin')
    @UseGuards(AuthGuard('jwt'), RolesGuard)