Как создать защиту динамических ролей, чтобы работать как в контроллерах, так и в обработчиках

#nestjs #nestjs-passport

#nestjs #nestjs-паспорт

Вопрос:

Я определяю защиту ролей следующим образом:

 import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Observable } from 'rxjs';
import { User } from './user.entity';

@Injectable()
export class RolesGuard implements CanActivate {
  constructor(
    private reflector: Reflector,
  ) { }

  async matchRoles(roles: string[], userRole: User["roles"]) {
    let match = false;

    if (roles.indexOf(userRole) > -1) {
      match = true;
    }

    return match
  }

  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    const roles = this.reflector.get<string[]>('roles', context.getClass());
    if (!roles) {
      return true;
    }
    const request = context.switchToHttp().getRequest();
    const user: User = request.user;

    return this.matchRoles(roles, user.roles)
  }
}
  

в этом примере ролей это работает только на уровне контроллера, подобном этому:

 @Controller('games')
@hasRoles('user')
@UseGuards(AuthGuard(), JwtGuard, RolesGuard)
export class GamesController {
...
  

Но я хочу, чтобы он работал динамически как с контроллером, так и с обработчиком.
таким образом, я могу применить @hasRoles('user') для каждого маршрута в контроллере и @hasRoles('admin') для некоторых маршрутов в этом контроллере.

Итак, для этого мне нужно изменить метод reflector с getClass на getHandler динамически.

Ответ №1:

У Nest Reflector есть встроенный метод для объединения набора метаданных на контроллерах и обработчиках маршрутов, с getAllAndMerge которым будут объединены метаданные из класса и метода. Чтобы использовать его, вы должны сделать что-то вроде

 const roles = this.reflector.getAllAndMerge(
  'roles',
  [
    context.getHandler(),
    context.getClass()
  ]
);
  

Если вы хотите получить только один набор метаданных и иметь запасной вариант (скажем, если вам нужны только метаданные обработчика, если они существуют, и если нет, получите метаданные класса), вы можете использовать getAllAndOverride аналогичным образом

 const roles = this.reflector.getAllAndOverride(
  'roles',
  [
    context.getHandler(),
    context.getClass()
  ]
);
  

Вы можете прочитать более подробно об этом здесь.