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
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);
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)