[英]Nestjs Roles Decorator: Crazy behaviour with getting user out of payload data
I am just trying to implement my Roles Decorator in Nestjs.我只是想在 Nestjs 中实现我的角色装饰器。 So far it went pretty well, until I wanted to compare the user of the payload data from the jwt-token to the required role.
到目前为止一切顺利,直到我想将来自 jwt-token 的有效负载数据的用户与所需的角色进行比较。 I can't explain how this is possible, but it is only possible to get the user and role out of the payload data, if i let the function return always true.
我无法解释这是怎么可能的,但只有让 function 返回始终为真,才能从有效负载数据中获取用户和角色。 After I set a condition the user is undefined.
在我设置条件后,用户未定义。 How is this even possible?
这怎么可能?
Here is my (shortened) user controller, where I use the Decorator:这是我的(缩短的)用户 controller,我在其中使用装饰器:
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('users')
export class UsersController {
constructor(private readonly userService: UserService) {}
private readonly logger = new Logger(LoggingService.name);
@Post('/create')
async create(@Body() createUserDto: CreateUserDto) {
const hashedPassword = await bcrypt.hash(createUserDto.password, 10);
createUserDto.password = hashedPassword
return this.userService.createUser(createUserDto);
}
@Roles(Role.SUPERADMIN)
@Get('/')
showUsers() {
return this.userService.getUsers();
}
And here is the roles decorator, with condition:这是角色装饰器,有条件:
import { CanActivate, ExecutionContext, Injectable, Logger } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Observable } from 'rxjs';
import { LoggingService } from 'src/services/logging/logging.service';
import { User } from 'src/user/schemas/user.schema';
import { Role } from '../role.enum';
import { ROLES_KEY } from '../decorators/roles.decorator';
import { Types } from 'mongoose';
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private readonly reflector: Reflector) {}
private readonly logger = new Logger(LoggingService.name);
canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
const roles = this.reflector.get<Role[]>(ROLES_KEY, context.getHandler());
// If there is no Roles-Decorator, just pass through
if (!roles) {
return true;
}
this.logger.debug("REQUIRED ROLES: ", roles)
const request = context.switchToHttp().getRequest();
const userRole = request.user?.roles;
const userID = request.user?.sub;
this.logger.debug("ROLES GUARD USER", userID);
this.logger.debug("USER ROLE", userRole);
// Else, check the request header if it matches
if (roles.includes(userRole)) {
return true;
} else { return false }
}
}
Logging output (when I try to access the route):记录 output (当我尝试访问路由时):
[Nest] 4460 - 25.11.2021, 18:56:33 DEBUG [LoggingService] REQUIRED ROLES:
[Nest] 4460 - 25.11.2021, 18:56:33 DEBUG [LoggingService] superadmin
[Nest] 4460 - 25.11.2021, 18:56:33 DEBUG [LoggingService] ROLES GUARD USER
[Nest] 4460 - 25.11.2021, 18:56:33 DEBUG [LoggingService] undefined
[Nest] 4460 - 25.11.2021, 18:56:33 DEBUG [LoggingService] USER ROLE
[Nest] 4460 - 25.11.2021, 18:56:33 DEBUG [LoggingService] undefined
But when I do this:但是当我这样做时:
// Else, check the request header if it matches
// if (roles.includes(userRole)) {
// return true;
// } else { return false }
return true;
The logging output is this:日志记录 output 是这样的:
[Nest] 39888 - 25.11.2021, 19:00:14 DEBUG [LoggingService] REQUIRED ROLES:
[Nest] 39888 - 25.11.2021, 19:00:14 DEBUG [LoggingService] superadmin
[Nest] 39888 - 25.11.2021, 19:00:14 DEBUG [LoggingService] ROLES GUARD USER
[Nest] 39888 - 25.11.2021, 19:00:14 DEBUG [LoggingService] 619962ad86e412dc06983a0e
[Nest] 39888 - 25.11.2021, 19:00:14 DEBUG [LoggingService] USER ROLE
[Nest] 39888 - 25.11.2021, 19:00:14 DEBUG [LoggingService] superadmin
The control-flow is top to bottom, right?控制流是从上到下的,对吧? Any help would be greatly appreciated!
任何帮助将不胜感激!
Using APP_GUARD
in any module that is registered by the application registers the guard as a global guard, that will run before every request.在应用程序注册的任何模块中使用
APP_GUARD
守卫注册为全局守卫,它将在每个请求之前运行。 What I would do is register two global guards, one for the JwtAuthGuard
one for the RolesGuard
, and implement a @JwtSkip()
decorator, that tells the JwtAuthGuard
that it can skip authentication on this route (would be the same for the RolesGuard
as it shouldn't have any roles associated with it我要做的是注册两个全局警卫,一个用于
JwtAuthGuard
一个用于RolesGuard
,并实现一个@JwtSkip()
装饰器,它告诉JwtAuthGuard
它可以跳过此路由上的身份验证(对于RolesGuard
与它相同不应该有任何与之相关的角色
I found the Solution!我找到了解决方案!
I had not registered the RolesGuard in a global context.我没有在全局上下文中注册 RolesGuard。 So I went ahead and put
所以我继续说
app.useGlobalGuards(new RolesGuard(new Reflector()));
in the main.ts.在 main.ts 中。 It then suddenly worked.
然后它突然起作用了。 And I modified the condition to pass the Guard as follows:
我修改了通过 Guard 的条件,如下所示:
// Else, check the request header if it matches
if (roles.some(r => r == userRole)) {
this.logger.log("ROLES GUARD: PASS")
return true;
} else {
this.logger.error("ROLES GUARD: DENIED")
return false
}
Hope this helps anyone!希望这对任何人都有帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.