如何使动态角色守卫在控制器和处理程序中都能工作

问题描述

我正在定义这样的角色守卫:

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

因此,我需要将反射器方法getClass动态更改为getHandler

解决方法

Nest的Reflector具有一个内置方法,可将{@ 1}}合并在控制器和路由处理程序上设置的元数据,该方法将合并类和方法中的元数据。要使用它,你会做类似的事情

getAllAndMerge

如果您只想获取一组元数据并进行后备操作(例如,如果只希望处理程序元数据存在,并且不获取类的元数据),则可以类似的方式使用const roles = this.reflector.getAllAndMerge( 'roles',[ context.getHandler(),context.getClass() ] );

getAllAndOverride

You can read more in-depth about it here

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...