【问题标题】:how to implement user guards in nestjs graphql如何在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",

标签: javascript graphql jwt nestjs graphql-js


【解决方案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
        }
      }
      

      【讨论】:

        猜你喜欢
        • 2021-06-23
        • 2020-03-24
        • 2019-06-07
        • 2020-03-21
        • 2019-12-17
        • 2020-05-22
        • 1970-01-01
        • 2020-08-01
        • 2019-09-28
        相关资源
        最近更新 更多