![](/img/trans.png)
[英]User is undefined on the context.switchToHttp().getRequest() nestjs
[英]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.