我正在设计一个用于特殊控制器的角色保护。我遵循文档的方法在app.module级别全局使用它。这是代码。
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors();
app.useGlobalGuards(new RoleGuard(new Reflector()));
await app.listen(3000);
}
现在,我的RoleGuard的Code工作正常,并在预期的时候返回console.log结果,只是应该由passport中间件添加的request.user不存在。这是警卫的代码:
export class RoleGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
const roles = this.reflector.get<string[]>('roles', context.getHandler());
if (!roles) {
console.log('no roles');
return true;
}
const request = context.switchToHttp().getRequest();
const user = request.user;
console.dir(user);
return this.matchRoles(roles, user);
}
console.dir显示未定义,但当尝试console.dr请求时,它工作正常,只是它不包含用户属性。
听起来你已经解决了自己的问题,AuthGuard
需要在RolesGuard
之前运行。原因是passport
负责设置req.user
属性,因此AuthGuard
(在后台使用passport(需要首先运行。所有Nest增强器都有一个定义的运行顺序,如请求生命周期页面中所记录的。首先运行全局增强子(通过app.useGlobal*()
或APP_*
结合的增强子(。然后是控制器级增强器,最后是方法级增强器。
为了允许全局设置RolesGuard
,您可以创建一个保护extends AuthGuard()
,并读取一些关于AuthGuard
是否应该触发的自定义元数据。如果元数据存在,则返回true
作为短路,如果不存在,则在自定义保护的canActivate
方法中返回super.canActivate()
。您可以设置此元数据,类似于设置角色元数据的方式,也在文档中概述。
将控制器下的Guard Decorator从main.ts移开,现在可以正确显示request.user对象。我假设passport中间件稍后会附加用户属性,因此它在应用程序的全局级别上是看不见的。我希望对这个问题有更多的了解,因为这只是我自己的假设
您可以尝试以下代码片段,它与您的代码几乎相似,所以我给出了整个片段:
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
// get the role of the request
const roles = this.reflector.get<Role[]>("roles", context.getHandler());
if (!roles) {
return true;
}
// now get the current user
const request = context.switchToHttp().getRequest();
const requestData = request;
return roles.some((role) => requestData.user.role.toLowerCase() === role);
}
}
对于我的案例,Role[]来自用户模型的userRole。这是我的用例:
export enum Role {
ADMIN = "admin",
USER = "user",
}
你需要从你的代码库中导入它。