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
相关产品推荐
相关产品推荐

