我正在制作一个用于特定控制器的角色防护。我遵循在 app.module 级别全局使用它的文档方式。这是代码。
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors();
app.useGlobalGuards(new RoleGuard(new Reflector()));
await app.listen(3000);
}
现在我的 RoleGuard 代码工作正常,并在预期时返回 console.logged 结果,只是护照中间件应添加的 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.dir 请求时它工作正常,只是它不包含用户属性。
听起来你找到了自己的问题,
AuthGuard
需要在RolesGuard
之前运行。这样做的原因是 passport
负责设置 req.user
属性,因此 AuthGuard
(在后台使用通行证)需要首先运行。所有 Nest 增强器都有一个定义的运行顺序,如请求生命周期页面中记录的那样。首先运行全局增强器(通过 app.useGlobal*()
或 APP_*
绑定的增强器)。然后是控制器级增强器,最后是方法级增强器。为了允许全局设置 RolesGuard
,您可以做的事情是创建一个
extends AuthGuard()
的防护,并读取一些有关 AuthGuard
是否应该触发的自定义元数据。如果元数据存在,则以短路形式返回 true
,如果不存在,则在自定义守卫的 super.canActivate()
方法中返回 canActivate
。您可以像设置角色元数据一样设置此元数据,文档中也有概述。 将控制器下的 Guard Decorator 移离 main.ts 现在可以正确显示 request.user 对象。我假设护照中间件稍后会附加用户属性,因此在应用程序的全局级别上看不到它。我希望对这个问题有更多的见解,因为这只是我自己的假设
您可以尝试以下代码片段,它与您的代码几乎相似,所以我给出整个片段:
@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",
}
您需要从代码库导入它。
确保 RoleGuard 不是 Global Guard。