如何在nestjs graphql中实现用户保护

Posted

技术标签:

【中文标题】如何在nestjs graphql中实现用户保护【英文标题】:how to implement user guards in nestjs graphql 【发布时间】:2020-08-10 04:47:31 【问题描述】:

我正在尝试获取当前用户,但在解析器中我未定义,在 jwt 策略中我使用令牌获取用户 ibject 但在解析器中用户未定义

身份验证保护

import  ExecutionContext, Injectable  from '@nestjs/common';
import  AuthGuard  from '@nestjs/passport';
import  GqlExecutionContext  from '@nestjs/graphql';
import  AuthenticationError  from 'apollo-server-core';
import  ExecutionContextHost  from '@nestjs/core/helpers/execution-context-host';

@Injectable()
export class GqlAuthGuard extends AuthGuard('jwt') 

    canActivate(context: ExecutionContext) 
        const ctx = GqlExecutionContext.create(context);
        const  req  = ctx.getContext();

        return super.canActivate(
            new ExecutionContextHost([req]),
        );
    

    handleRequest(err: any, user: any) 
        if (err || !user) 
            throw err || new AuthenticationError('GqlAuthGuard');
        
        return user;
    



用户装饰器

import createParamDecorator from '@nestjs/common';

export const CurrentUser = createParamDecorator(
    (data, req) =>  req.user )
;

应用模块

@Module(
  imports: [
      PassportModule.register( defaultStrategy: 'jwt' ),
      JwtModule.register(
          signOptions: 
              expiresIn: 3600,
          ,
      ),
      SharedModule,
      AuthModule,
      GraphQLModule.forRoot(
          autoSchemaFile: 'schema.gql',
          context: ( req ) => ( req )
      ),
      MongooseModule.forRoot(process.env.MONGO_URI,
        
          useNewUrlParser: true ,
          useUnifiedTopology: true
        ),
    // RewardsModule,
    OrdersModule,
  ],
  controllers: [AppController],
  providers: [AppService],
)
export class AppModule 

解析器

import User from "src/types/user";
import GqlAuthGuard from "../guards/graphql.auth.guard";

@Resolver()
export class OrdersResolver 
    constructor(
        private orderService: OrdersService
    ) 
    

    @Query(returns => [Order])
    @UseGuards(GqlAuthGuard)
    listOrders(@CurrentUser() user: User): Promise<Order> 
        console.log(user)
        return this.orderService.listOrdersByUser(user.id);
    


我也尝试实施这里解释的解决方案NestJS Get current user in GraphQL resolver authenticated with JWT,但我仍然遇到同样的错误

【问题讨论】:

快速提问:您的 Nest 版本是什么?在 v6 和 v7 之间,createParamDecorator 函数发生了变化。 这些是nestjs版本 "@nestjs/common": "^7.0.0", "@nestjs/core": "^7.0.0", "@nestjs/graphql": "^ 7.3.4”、“@nestjs/jwt”:“^7.0.0”、“@nestjs/mongoose”:“^6.4.0”、“@nestjs/passport”:“^7.0.0”、“@nestjs /platform-express": "^7.0.0", "@nestjs/swagger": "^4.5.1", 【参考方案1】:

在 Nest v7 中,createParamDecorator 函数得到了更新。现在,而不是使用

export const CurrentUser = createParamDecorator(
    (data, req) =>  req.user )
;

你应该改用这样的东西:

export const User = createParamDecorator(
  (data: unknown, ctx: ExecutionContext) => 
    const gqlCtx = GqlExecutionContext.create(ctx);
    const request = gqlCtx.getContext().req;
    return request.user;
  ,
);

为此,您还需要

context: (req) => (req)

在您的 GraphqlModule 配置中。

【讨论】:

【参考方案2】:

这是完整的代码:

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

  canActivate(context: ExecutionContext): boolean 
    const ctx = GqlExecutionContext.create(context);

    const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);

    if (!requiredRoles) 
      return true;
    

    const  user  = ctx.getContext().req;
    return requiredRoles.some((role) => user.role?.includes(role));
  

【讨论】:

【参考方案3】:

这是我根据文档用于GraphqlJwtAuthGuard 的内容:

@Injectable()
export class GqlJwtAuthGuard extends AuthGuard('jwt') 
  constructor(private reflector: Reflector) 
    super();
  

  canActivate(ctx: ExecutionContext) 
    const context = GqlExecutionContext.create(ctx);
    const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);
    if (isPublic) 
      return true;
    
    const  req  = context.getContext();
    return super.canActivate(new ExecutionContextHost([req])); // NOTE
  

【讨论】:

以上是关于如何在nestjs graphql中实现用户保护的主要内容,如果未能解决你的问题,请参考以下文章

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

是否可以在 GraphQL 中实现多个接口?

有啥方法可以访问 NestJS 守卫中处理程序方法的参数?

在 GraphQL 服务器中实现访问控制的好模式是啥?

如何在 GraphQl JS 中实现带有破折号的枚举

如何在 GraphQL HotChocolate 中实现订阅?