Владислав
Владислав

Reputation: 111

Why does the Nest decorator work for any request, even when the decorator is not present?

I pointed out the decorator in one place, but it didn't work at all. Then, I connected the guardian to the module as shown in the documentation. Now, the guardian is processing any request.

export const Permissions = (...permissions: PermissionEnum[]) =>
  SetMetadata('permissions', permissions);
@Injectable()
export class PermissionGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    const requirePermissions = this.reflector.getAllAndOverride<
      PermissionEnum[]
    >('permissions', [context.getHandler(), context.getClass()]);
    console.log(requirePermissions, 'requirePermissions');
    if (!requirePermissions) {
      throw new HttpException(
        lang.ru.http_exceptions.forbidden,
        HttpStatus.FORBIDDEN,
      );
    }

    const user = context.switchToHttp().getRequest();
    //console.log(context.switchToHttp(), 'switchToHttp');
    //console.log(context.switchToHttp().getRequest(), 'getRequest');
    return false;
  }
}
  @HttpCode(201)
  @UseGuards(JwtAuthGuard)
  @Permissions(PermissionEnum.USER_VIEW)
  @Get('/users')
  getAll(@Query() query: AdminUserQueryDto) {
    return this.adminService.getUsers(query);
  }
@Module({
 ...
  providers: [RoleService, { provide: APP_GUARD, useClass: PermissionGuard }],
  ...
})
export class RoleModule {}

Is this how it should be?

Can you tell me how I can make the guard work only on those routes where the decorator is present?

Upvotes: 0

Views: 51

Answers (1)

Rijin
Rijin

Reputation: 954

You are injecting your guard to the module, so it will apply for every controller and every route handler of that module. Instead you can use the @UseGuards decorator for each route handler.

@HttpCode(201)
@UseGuards(JwtAuthGuard)
@Permissions(PermissionEnum.USER_VIEW)
@UseGuards(PermissionGuard)
@Get('/users')
getAll(@Query() query: AdminUserQueryDto) {
  return this.adminService.getUsers(query);
}

If you don't want to use both @Permissions and @UseGuards decorators, you can use the decorator composition option. Using that feature you can combine both decorator and create a new one.

import { applyDecorators } from '@nestjs/common';

export function PermissionsWithGuard(...permissions: PermissionEnum[]) {
  return applyDecorators(
    Permissions(permissions),
    UseGuards(PermissionGuard),
  );
}

Then in your controller

 @HttpCode(201)
 @UseGuards(JwtAuthGuard)
 @PermissionsWithGuard(PermissionEnum.USER_VIEW)
 @Get('/users')
 getAll(@Query() query: AdminUserQueryDto) {
   return this.adminService.getUsers(query);
 }

Or else you can directly modify your Permission decorator to apply the guard too.

import { applyDecorators } from '@nestjs/common';
    
export function PermissionsWithGuard(...permissions: PermissionEnum[]) {
  return applyDecorators(
    SetMetadata('permissions', permissions),
    UseGuards(PermissionGuard),
  );
}

Upvotes: 0

Related Questions