NestJS:如何在从 JWT AuthGuard 扩展的 GraphQL 自定义 Guard 中从请求中获取用户

Posted

技术标签:

【中文标题】NestJS:如何在从 JWT AuthGuard 扩展的 GraphQL 自定义 Guard 中从请求中获取用户【英文标题】:NestJS: How to get User from the request in a GraphQL custom Guard which extends from JWT AuthGuard 【发布时间】:2020-03-26 00:01:10 【问题描述】:

我使用 Passport 和 GraphQL,如果我使用自己的自定义保护来获取用户的角色,它就不起作用。我无法通过 Guard 中的请求访问用户,这是故意的吗?我认为它应该是请求的一部分(我对 NestJS 完全陌生),为什么我不能得到它?我想直接从用户对象中获取用户的角色,并且只允许具有 Admin 的用户访问特定路由,例如完整的用户列表。

这是我的 GraphQL 守卫,控制台日志总是返回 undefined

@Injectable()
export class GraphqlPassportAuthGuard extends AuthGuard('jwt') 
  roles: string[];

  constructor(roles?: string | string[]) 
    super();
    this.roles = Array.isArray(roles) ? roles : [roles];
  

  canActivate(context: ExecutionContext): boolean 
    const ctx = GqlExecutionContext.create(context);
    const req = ctx.getContext().req;
    console.log('graphql guard user', req && req.user)
    return true;
  

  getRequest(context: ExecutionContext) 
    const ctx = GqlExecutionContext.create(context);
    const req = ctx.getContext().req;
    console.log('graphql guard user', req && req.user)
    return req;
  

我尝试使用以下代码

export const CurrentUser = createParamDecorator(
  (data, [root, args, ctx, info]) => 
    return ctx.req.user;
  ,
);

@Resolver()
export class UsersResolver 
  constructor()   

  @Query(() => UserDto)
  @UseGuards(GraphqlPassportAuthGuard)
  whoAmI(@CurrentUser() user: User) 
    return user;
  

app.module.ts

@Module(
  imports: [
    GraphQLModule.forRoot(
      autoSchemaFile: 'schema.gql',
      context: ( req ) => ( req ),
    ),
    // ...
);

我可以使用自定义装饰器从@CurrentUser() 获取用户,但我无法在警卫内获取用户对象。我正在尝试从请求中获取用户,但这是否可能在 Guard 中?我尝试了很多东西,我不知道该怎么做了。

我还尝试使用不同的代码执行另一个角色保护,我再次尝试从请求中获取用户,但我无法从请求中获取用户。

@Injectable()
export class RolesGuard implements CanActivate 
  constructor(private readonly reflector: Reflector)  

  canActivate(context: ExecutionContext): boolean 
    const handler = context.getHandler();
    const http = context.switchToHttp();
    const request = context.switchToHttp().getRequest();
    const roles = this.reflector.get<string[]>('roles', context.getHandler());
    console.log('rolesGuard', roles, request && request.user)
    if (!roles || !request || !request.user) 
      return true;
    
    const user = request && request.user;
    const hasRole = () =>
      user.roles.some(role => !!roles.find(item => item === role));

    return user && user.roles && hasRole();
  

【问题讨论】:

【参考方案1】:

在您的GraphqlPassportAuthGuard.canActivate() 上,您应该调用super.canActivate(context),这是@nestjs/passport AuthGuard 将用户放入请求对象的位置。

如果由于某种原因,您不希望在用户未通过身份验证时抛出守卫,您还必须覆盖 AuthGuard.handleRequest(err, user, info, context)

【讨论】:

抱歉耽搁了,我刚试过这个,我仍然有相同的结果undefined,我应该在super.canActivate之后仍然调用相同的2行吗?第二行ctx.getContext().req 仍然没有我正在寻找的用户。您介意提供canActive 方法的完整代码吗?我是要删除某些东西还是调用其他东西?我对 NestJS 完全陌生,我有点困惑。我的主要目标是获取用户的角色并在用户没有必要角色时阻止他 你应该 await 获取 super.canActivate 因为它返回一个 Promise,抱歉我没有在我的原始答案中提到。所以定义canActivateasync并调用await super.canActivate(context)。还要记住将返回类型更改为Promise&lt;boolean&gt;

以上是关于NestJS:如何在从 JWT AuthGuard 扩展的 GraphQL 自定义 Guard 中从请求中获取用户的主要内容,如果未能解决你的问题,请参考以下文章

PassportJS、NestJS:AuthGuard('jwt') 的 canActivate 方法

NestJS:使用 JWT 向 AuthGuard 添加验证选项

我在我的 nestJS 应用程序(使用 authGuard)中使用了 passport-jwt 身份验证策略,如何访问我的控制器中的令牌有效负载?

在没有 AuthGuard 的路由上获取 nestjs 中的当前用户

@@ nestjs / jwt-无法读取未定义的属性'挑战'

处理 GraphQL 和 REST 的 NestJS AuthGuard