You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NestJS中nest-keycloak-connect无法识别GraphQL ExecutionContext求助

NestJS中nest-keycloak-connect适配GraphQL授权问题解决

问题概述

使用nest-keycloak-connect为NestJS GraphQL接口实现用户授权时,携带Authorization请求头调用查询接口,返回错误:[Keycloak] Empty JWT, unauthorized。查看nest-keycloak-connect源码,其已处理HTTP和GraphQL上下文,但仍无法正确识别GraphQL请求中的JWT。

关键代码参考

nest-keycloak-connect上下文提取逻辑

export const extractRequest = (context: ExecutionContext): [any, any] => {
  let request: any, response: any;

  // Check if request is coming from graphql or http
  if (context.getType() === 'http') {
    // http request
    const httpContext = context.switchToHttp();

    request = httpContext.getRequest();
    response = httpContext.getResponse();
  } else if (context.getType<GqlContextType>() === 'graphql') {
    let gql: any;
    // Check if graphql is installed
    try {
      gql = require('@nestjs/graphql');
    } catch (er) {
      throw new Error('@nestjs/graphql is not installed, cannot proceed');
    }

    // graphql request
    const gqlContext = gql.GqlExecutionContext.create(context).getContext();

    request = gqlContext.req;
    response = gqlContext.res;
  }

  return [request, response];
};

当前授权模块配置

@Module({
  imports: [
    MongooseModule.forRoot('mongodb://localhost/Products'),

    KeycloakConnectModule.register({
      authServerUrl: 'http://localhost:8080/auth',
      realm: 'users',
      clientId: 'users-service',
      secret: 'h1xAJnShNwPmxzySR8Y0d3fLh27iwPPh',
      policyEnforcement: PolicyEnforcementMode.PERMISSIVE, // optional
      tokenValidation: TokenValidation.ONLINE, // optional
    }),

    GraphQLModule.forRoot<ApolloFederationDriverConfig>({
      driver: ApolloFederationDriver,
      autoSchemaFile: true,
    }),

    ProductModule,
    ProductImageModule,
    ProductAttributeModule,
  ],
  providers: [
    {
      provide: APP_GUARD,
      useClass: AuthGuard,
    },
    {
      provide: APP_GUARD,
      useClass: ResourceGuard,
    },
    {
      provide: APP_GUARD,
      useClass: RoleGuard,
    },
  ],
  controllers: [],
})
export class AppModule {}

Resolver示例代码

//FindAll
@Query(() => [Product])
@Roles({roles: ['user']})
async products() {
  const products = await this.productService.findAll();
  return products;
}

请求头示例

{
  "Authorization":"eyJhbGciOiJSUzI1N..."
}

解决方案

1. 配置GraphQL上下文传递HTTP请求对象

修改GraphQLModule.forRoot的配置,添加context选项,将HTTP请求和响应对象注入到GraphQL上下文中:

GraphQLModule.forRoot<ApolloFederationDriverConfig>({
  driver: ApolloFederationDriver,
  autoSchemaFile: true,
  // 注入HTTP请求响应到GraphQL上下文
  context: ({ req, res }) => ({ req, res }),
}),

说明:nest-keycloak-connect处理GraphQL请求时,需要从gqlContext.req中获取请求对象读取Authorization头。默认情况下Apollo Server不会自动传递req和res到GraphQL上下文,导致无法提取JWT。

2. 修正Authorization请求头格式

确保请求头的Authorization字段遵循Bearer <token>的标准格式,示例:

{
  "Authorization": "Bearer eyJhbGciOiJSUzI1N..."
}

说明:nest-keycloak-connect默认解析带有Bearer前缀的授权头,缺少前缀会被判定为空JWT。

3. 确认Guard执行顺序(可选)

保证AuthGuard在所有Guard中最先执行,先完成JWT验证,再进行资源和角色校验:

providers: [
  {
    provide: APP_GUARD,
    useClass: AuthGuard, // 优先验证JWT有效性
  },
  {
    provide: APP_GUARD,
    useClass: ResourceGuard, // 校验资源权限
  },
  {
    provide: APP_GUARD,
    useClass: RoleGuard, // 校验角色权限
  },
],

内容的提问来源于stack exchange,提问作者g_m

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 19:33:23