如何制作动态角色守卫,在控制器和处理程序中工作
How to make a dynamic roles guard, to work in both controllers and handlers
我正在这样定义角色守卫:
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
有一个 built-in 方法将控制器和路由处理程序上的元数据集与 getAllAndMerge
合并,这将合并来自 class 的元数据和该方法.要使用它,你会做类似
的事情
const roles = this.reflector.getAllAndMerge(
'roles',
[
context.getHandler(),
context.getClass()
]
);
如果您只想获取一组元数据并进行回退(例如,如果您只想要处理程序元数据,如果它存在,如果不获取 class 的元数据),您可以使用 getAllAndOverride
以类似的方式
const roles = this.reflector.getAllAndOverride(
'roles',
[
context.getHandler(),
context.getClass()
]
);
我正在这样定义角色守卫:
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
有一个 built-in 方法将控制器和路由处理程序上的元数据集与 getAllAndMerge
合并,这将合并来自 class 的元数据和该方法.要使用它,你会做类似
const roles = this.reflector.getAllAndMerge(
'roles',
[
context.getHandler(),
context.getClass()
]
);
如果您只想获取一组元数据并进行回退(例如,如果您只想要处理程序元数据,如果它存在,如果不获取 class 的元数据),您可以使用 getAllAndOverride
以类似的方式
const roles = this.reflector.getAllAndOverride(
'roles',
[
context.getHandler(),
context.getClass()
]
);