Quarkus中GraphQL订阅接口的身份认证问题(graphql-ui)
解决Quarkus + SmallRye GraphQL订阅接口的身份认证问题
问题场景
你在Quarkus中使用SmallRye GraphQL实现了包含查询和订阅的接口,查询接口通过添加Authorization: Bearer <token>请求头可正常完成认证,但调用订阅接口时即便使用相同请求头配置,仍返回unauthorized错误。
核心原因
GraphQL订阅基于WebSocket协议,其认证流程与HTTP查询存在差异:订阅的初始连接依赖HTTP握手请求建立,但Quarkus默认安全配置可能未覆盖WebSocket握手阶段的认证逻辑,导致令牌无法被正确验证;部分GraphQL UI工具也可能未将HTTP请求头传递到WebSocket握手请求中。
解决方案
1. 配置Quarkus安全规则覆盖GraphQL WebSocket路径
在application.properties中添加安全规则,确保/graphql路径的WebSocket握手请求触发认证流程:
# 匹配GraphQL的WebSocket握手路径 quarkus.http.auth.permission.graphql-websocket.paths=/graphql # 要求该路径的请求必须经过认证 quarkus.http.auth.permission.graphql-websocket.policy=authenticated
2. 手动处理WebSocket握手阶段的令牌验证
如果默认安全过滤器未处理WebSocket请求,可创建一个请求拦截器,在握手阶段提取并验证令牌:
import jakarta.ws.rs.container.ContainerRequestContext; import jakarta.ws.rs.container.ContainerRequestFilter; import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.ext.Provider; @Provider public class WebSocketAuthFilter implements ContainerRequestFilter { @Override public void filter(ContainerRequestContext requestContext) { // 判断是否为WebSocket握手请求 String upgradeHeader = requestContext.getHeaderString("Upgrade"); if (upgradeHeader != null && upgradeHeader.equalsIgnoreCase("websocket")) { String authHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION); // 验证Bearer令牌格式 if (authHeader == null || !authHeader.startsWith("Bearer ")) { requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build()); return; } String token = authHeader.substring(7); // 集成Quarkus的JWT验证逻辑,示例:若验证失败则终止请求 // if (!isValidToken(token)) { // requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build()); // } } } // 自定义令牌验证方法 // private boolean isValidToken(String token) { // // 实现你的JWT验证逻辑 // } }
3. 确保订阅方法能获取认证上下文
在订阅类中注入SecurityContext,手动验证当前会话的认证状态:
import jakarta.inject.Inject; import jakarta.ws.rs.core.SecurityContext; import org.eclipse.microprofile.graphql.GraphQLApi; import org.eclipse.microprofile.graphql.Query; import io.quarkus.security.Authenticated; import io.smallrye.graphql.api.Subscription; import java.util.List; import org.reactivestreams.Publisher; @GraphQLApi @Authenticated public class MyGraphQL { @Inject SecurityContext securityContext; @Query("getInformation") public List<MyInformation> getMyInformation(int id) { // 查询业务逻辑 return null; } @Subscription("informationStream") public Publisher<MyInformation> getMyInformationStream() { // 验证当前用户是否已认证 if (securityContext.getUserPrincipal() == null) { throw new SecurityException("未授权访问订阅接口"); } // 订阅业务逻辑 return null; } }
4. 验证GraphQL UI的WebSocket请求头配置
部分版本的Quarkus GraphQL UI(graphql-ui)不会自动将HTTP请求头传递到WebSocket握手请求中,你可以:
- 在GraphQL UI的"Headers"设置中手动添加
Authorization头; - 使用Postman、GraphQL Playground等支持WebSocket请求头的工具测试订阅接口。
内容的提问来源于stack exchange,提问作者Rafael
相关产品推荐
相关产品推荐

