nestjs graphql set context 登录拦截器后

问题描述 投票:0回答:1

我希望

@Context
托管一些身份验证信息,例如令牌、用户、.. 我创建了一个
TGqlContext
类型,它在初始化 graphql

时被传递
export type TGqlContext = {
  req: Request;
  res: Response;
  accessToken: string;
  refreshToken: string;
  user?: UserDTO | undefined;
};

GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      include: [ProductsModule, AuthModule, TransactionsModule],
      buildSchemaOptions: {
        dateScalarMode: "timestamp",
      },
      autoSchemaFile: true,
      context: (ctx: TGqlContext) => ctx,
    }),

成功登录后,我想使用身份验证数据设置上下文。我正在尝试使用拦截器,因为它可以访问解析器响应。

虽然登录解析器的结果被很好地拦截,并且没有未定义,但在某些查询中使用@Context时,上下文数据仍然是未定义的。

我如何在登录后设置这些上下文值?

登录突变,带有拦截器

@UseInterceptors(LoggingInterceptor)
  @Mutation(() => AuthDTO)
  async login(@Args("credentials") credentials: AuthLoginInputType): Promise<AuthDTO> {
    const log = await this.authService.login(credentials);

    if (log.isValid) {
      this.authService.accessToken = log.accessToken;
      this.authService.refreshToken = log.refreshToken;
      this.authService.user = log.user;

      return {
        accessToken: log.accessToken,
        refreshToken: log.refreshToken,
        user: log.user,
      };
    } else {
      this.authService.accessToken = "";
      this.authService.refreshToken = "";
      this.authService.user = undefined;

      throw new HttpException(`${log.error} - ${log.message}`, log.httpStatus);
    }
  }

拦截器

export class LoggingInterceptor implements NestInterceptor {
  private readonly logger = new Logger(LoggingInterceptor.name);

  constructor() {
    this.logger.log("inter");
  }

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> | Promise<Observable<any>> {
    const ctx = GqlExecutionContext.create(context).getContext<TGqlContext>();
    const resu = next.handle().pipe(
      map((res: TGqlContext) => {
        this.logger.log(res.accessToken); //<--- here the data are NOT undefined
        ctx.accessToken = res.accessToken;
        ctx.refreshToken = res.accessToken;
        ctx.user = res.user;
        return res;
      }),
      catchError((err: any) => {
        throw new HttpException(err.message, HttpStatus.BAD_REQUEST);
      })
    );

    return resu;
  }
}

尝试获取这些上下文数据的查询示例

@Query(() => AuthDTO)
  async me(@Context() ctx: TGqlContext): Promise<AuthDTO> {
    this.logger.log(ctx.accessToken); // <--- here data is undefined...
    const mee: AuthDTO = {
      accessToken: this.authService.accessToken,
      refreshToken: this.authService.refreshToken,
      user: this.authService.user,
    };

    return mee;
  }
graphql nestjs interceptor resolver
1个回答
0
投票

我通过在请求的会话中添加 auth 数据找到了解决方案,而不是在 graphql 上下文的根目录中添加这些数据。在我看来这不是最有价值的解决方案

GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      include: [ProductsModule, AuthModule, TransactionsModule],
      buildSchemaOptions: {
        dateScalarMode: "timestamp",
      },
      autoSchemaFile: true,
      context: ({ req }: { req: Request }) => ({ req }),
    }),

在登录解析器中

@Mutation(() => AuthDTO)
  async login(@Context() ctx: TGqlContext, @Args("credentials") credentials: AuthLoginInputType): Promise<AuthDTO> {
    const log = await this.authService.login(credentials);

    if (log.isValid) {
      this.authService.accessToken = log.accessToken;
      this.authService.refreshToken = log.refreshToken;
      this.authService.user = log.user;

      ctx.req.session.accessToken = log.accessToken;
      ctx.req.session.refreshToken = log.refreshToken;
      ctx.req.session.user = log.user;

      return {
        accessToken: log.accessToken,
        refreshToken: log.refreshToken,
        user: log.user,
      };
    } else {
      throw new HttpException(`${log.error} - ${log.message}`, log.httpStatus);
    }
  }
© www.soinside.com 2019 - 2024. All rights reserved.