Quarkus中如何将WebSocket的JWT查询参数转为Authorization头
问题背景
基于Quarkus开发时,需要将WebSocket请求查询参数里的jwt值转换为Authorization: Bearer <JWT>请求头。由于WebSocket客户端是浏览器,无法直接设置请求头。
尝试过的无效方案
我编写了一个Scala请求过滤器,但它仅对REST API生效,WebSocket握手请求不会触发该过滤器:
class WebSocketJwtFilter: @ServerRequestFilter(preMatching = true) def preMatchingFilter(ctx: ContainerRequestContext): Unit = val info = ctx.getUriInfo val path = info.getPath if path.startsWith("/ws/") then val jwt = info.getQueryParameters.getFirst("jwt") if jwt != null && !jwt.isBlank then ctx.getHeaders.putSingle("Authorization", s"Bearer $jwt")
期望实现
不想在@WebSocket类中手动处理认证逻辑,希望借助Quarkus安全机制,实现类似以下的WebSocket认证效果,直接使用@RolesAllowed和@Claim这类注解完成权限控制与Claims注入:
@WebSocket(path = "/ws/v1/foo") @RequestScoped @RolesAllowed(Array("user")) class RtcWs: @Inject @Claim(standard = sub) private[poc] var subject: String = uninitialized
解决方案
Quarkus的@ServerRequestFilter默认仅处理REST端点,要让它作用于WebSocket握手请求,需做以下调整:
1. 修改过滤器,指定匹配WebSocket路径
给过滤器添加@MatchingPath注解,明确匹配WebSocket路径前缀,确保握手请求被拦截,同时声明正确的作用域:
import jakarta.ws.rs.container.ContainerRequestContext import jakarta.ws.rs.container.ServerRequestFilter import jakarta.ws.rs.core.UriInfo import jakarta.ws.rs.MatchingPath import jakarta.enterprise.context.ApplicationScoped @ApplicationScoped class WebSocketJwtFilter: @ServerRequestFilter(preMatching = true) @MatchingPath("/ws/*") def preMatchingFilter(ctx: ContainerRequestContext): Unit = val info: UriInfo = ctx.getUriInfo val jwt = info.getQueryParameters.getFirst("jwt") if jwt != null && !jwt.isBlank then ctx.getHeaders.putSingle("Authorization", s"Bearer $jwt")
2. 确保项目引入JWT安全扩展
要让@RolesAllowed和@Claim生效,需确保项目已引入Quarkus JWT扩展:
- Maven依赖:
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-smallrye-jwt</artifactId> </dependency>
- Gradle依赖:
implementation 'io.quarkus:quarkus-smallrye-jwt'
3. 验证逻辑
当WebSocket发起握手请求时,过滤器会拦截所有路径以/ws/开头的请求,提取jwt查询参数并注入Authorization头。之后Quarkus安全机制会自动完成JWT验证、Claims解析,以及@RolesAllowed的权限检查,最终你的RtcWs类就能正常注入subject并实现权限控制。
内容的提问来源于stack exchange,提问作者wiradikusuma
相关产品推荐
相关产品推荐

