繁体   English   中英

NestJs - 无法在 RolesGuard 中获取用户上下文

[英]NestJs - Unable to get user context in RolesGuard

我使用 NestJS 作为客户端 API 的框架。 在框架内,我们使用了一个运行良好的非常标准的 Passport/JWT 身份验证基础设施。 当找到承载令牌时,我们的 AuthGuard 正在触发,并且在安全的 API 端点中,我可以通过“@Res() 请求”注入 HTTP 上下文并访问包含我的 Z794349 令牌的有效负载的“request.user”属性.

最重要的是,我们正在尝试以与文档中提供的示例代码和 GitHub 上的一些示例项目非常相似的方式实现“RolesGuard”(其中没有一个实际使用此防护,但它们将其包含为示例防护)。

我们的问题是,我们的 AuthGuard 触发并验证 Jwt 令牌,然后我们的 RolesGuard 触发,但它传递的请求 object 没有附加到请求的用户元数据。

我们 RolesGuard 中的关键代码是:

    const request = context.switchToHttp().getRequest();
    const user = request.user;

    if (!user) {
        return false;
    }

在上面的截图中,用户总是假的。 是否有人在 Nest 中编写了基于角色/权限的守卫,成功访问了当前用户的 scope? 所有代码都在触发,并且所有内容都显示正确注册。

-凯文

最终,这似乎是守卫的排序问题,而且看起来不容易解决(没有框架允许对排序进行一些控制)。

我的希望是全局注册 RolesGuard,但这会导致它首先注册并首先触发。

@UseGuards(AuthGuard('jwt'), RolesGuard)
@Roles('admin')

如果我在端点级别注册它并将其放在 AuthGuard 之后,那么它会第二次触发,并且我会在警卫本身中获得我期望的用户上下文。 它并不完美,但它有效。

-凯文

在端点级别注册 RoleGuard 并将其放在 AuthGuard 之后,然后它会触发第二次,我会在警卫本身中获得我期望的用户上下文。 不要在模块中注册 RoleGuard 会导致它首先注册并首先触发。

*.module.ts

imports: [],
  providers: [{provide: APP_GUARD, useClass: RolesGuard} ,],  // remove guard
  controllers: [],
  exports: [],

让您的 RolesGuard 扩展 AuthGuard('StrategyName') 然后调用 super.canActivate 例如:

@Injectable()
export class RolesGuard extends AuthGuard('jwt') {
    async canActivate(context: ExecutionContext): Promise<boolean> {

        // call AuthGuard in order to ensure user is injected in request
        const baseGuardResult = await super.canActivate(context);
        if(!baseGuardResult){
            // unsuccessful authentication return false
            return false;
        }

        // successfull authentication, user is injected
        const {user} = context.switchToHttp().getRequest();
    }
}

换句话说,您必须先进行身份验证,然后再进行授权

如果其他人偶然发现了这个问题:将多个守卫放入一个@UseGuards装饰器可以工作,但是如果您想将它们分开(例如,如果您使用自定义装饰器),您可以通过放置让第二个守卫访问req.user将用户置于请求对象上的@UseGuards调用之前,如下例所示:

@RestrictTo(UserAuthorities.admin)
@UseGuards(JwtAuthGuard)
@Get("/your-route")

这似乎是装饰器在 TypeScript 中工作方式的结果。

您还可以使用多个角色进行基于角色的身份验证。

在用户解析器中

import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { UseGuards } from '@nestjs/common';
import { RolesGuard } from 'src/guards/auth.guard';

@UseGuards(new RolesGuard(['admin']))
@Resolver()
export class UserResolver { ... }

在角色卫士中

import { ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
import { GqlExecutionContext } from '@nestjs/graphql';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class RolesGuard extends AuthGuard('jwt') {
  constructor(private roles: string[] | null) {
    super();
  }

  canActivate(context: ExecutionContext) {
    const ctx = GqlExecutionContext.create(context);
    const { req } = ctx.getContext();
    return super.canActivate(new ExecutionContextHost([req]));
  }

  handleRequest(err: any, user: any, info: string) {
    if (!this.roles) {
      return user || null;
    }

    if (!user) {
      throw new UnauthorizedException('Not Valid User.');
    }

    const role = user.role;
    const doesRoleMatch = this.roles.some(r => r === role);
    if (!doesRoleMatch) {
      throw new UnauthorizedException('Not Valid User.');
    }
    return user;
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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