簡體   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