简体   繁体   English

Nestjs Roles Decorator:让用户脱离有效负载数据的疯狂行为

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM