如何创建动态角色防护,以在控制器和处理程序中工作

Yas*_*idi 4 nestjs nestjs-passport

我定义一个角色守卫是这样的:

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)
  }
}
Run Code Online (Sandbox Code Playgroud)

在此角色示例中,它仅在控制器级别有效,如下所示:

@Controller('games')
@hasRoles('user')
@UseGuards(AuthGuard(), JwtGuard, RolesGuard)
export class GamesController {
...
Run Code Online (Sandbox Code Playgroud)

但我希望它能够在控制器级别和处理程序级别动态地工作。所以我可以@hasRoles('user')为控制器中的每条路线以及@hasRoles('admin')该控制器中的某些路线应用 a 。

因此,要做到这一点,我需要将反射器方法从 更改getClassgetHandler动态。

Jay*_*iel 8

NestReflector有一个内置方法来合并控制器和路由处理程序上设置的元数据,getAllAndMerge该方法将合并来自类和方法的元数据。要使用它,你会做类似的事情

const roles = this.reflector.getAllAndMerge(
  'roles',
  [
    context.getHandler(),
    context.getClass()
  ]
);
Run Code Online (Sandbox Code Playgroud)

如果您只想获取一组元数据并有一个后备(例如,如果您只想要处理程序元数据(如果存在),如果不获取类的元数据),您可以getAllAndOverride以类似的方式使用

const roles = this.reflector.getAllAndOverride(
  'roles',
  [
    context.getHandler(),
    context.getClass()
  ]
);
Run Code Online (Sandbox Code Playgroud)

您可以在这里阅读更深入的内容