微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Quarkus JWKS 刷新阻止

如何解决Quarkus JWKS 刷新阻止

我在 Quarkus 中使用 RestEasy 反应式创建了 REST 资源。它需要 JWT 并在方法中使用此注释进行保护:

@RolesAllowed({"read.access"}) 

我在属性中定义了 JWKS URL:

  mp:
    jwt:
      verify:
        publickey:
          location: http://my.server/jwks

问题在于它使用 Java HttpClient 以阻塞方式刷新 JWKS,这会在调用反应式 REST 资源时导致这种情况:

 io.vertx.core.VertxException: Thread blocked
        at java.base@11.0.2/java.net.PlainSocketImpl.socketConnect(Native Method)
        at java.base@11.0.2/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399)
        at java.base@11.0.2/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242)
        at java.base@11.0.2/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:224)
        at java.base@11.0.2/java.net.socket.connect(Socket.java:591)
        at java.base@11.0.2/sun.net.NetworkClient.doConnect(NetworkClient.java:177)
        at java.base@11.0.2/sun.net.www.http.HttpClient.openServer(HttpClient.java:474)
        at java.base@11.0.2/sun.net.www.http.HttpClient.openServer(HttpClient.java:569)
        at java.base@11.0.2/sun.net.www.http.HttpClient.<init>(HttpClient.java:242)
        at java.base@11.0.2/sun.net.www.http.HttpClient.New(HttpClient.java:341)
        at java.base@11.0.2/sun.net.www.http.HttpClient.New(HttpClient.java:362)
        at java.base@11.0.2/sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1242)
        at java.base@11.0.2/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1181)
        at java.base@11.0.2/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1075)
        at java.base@11.0.2/sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:1009)
        at java.base@11.0.2/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1581)
        at java.base@11.0.2/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1509)
        at java.base@11.0.2/java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:527)
        at org.jose4j.http.Get.get(Get.java:80)
        at org.jose4j.jwk.HttpsJwks.refresh(HttpsJwks.java:204)
        at io.smallrye.jwt.auth.principal.AbstractKeyLocationResolver.isHttpsJwksInitialized(AbstractKeyLocationResolver.java:100)
        at io.smallrye.jwt.auth.principal.KeyLocationResolver.initializeKeyContent(KeyLocationResolver.java:88)
        at io.smallrye.jwt.auth.principal.KeyLocationResolver.<init>(KeyLocationResolver.java:44)
        at io.smallrye.jwt.auth.principal.DefaultJWTTokenParser.getVerificationKeyResolver(DefaultJWTTokenParser.java:226)
        at io.smallrye.jwt.auth.principal.DefaultJWTTokenParser.parseClaims(DefaultJWTTokenParser.java:95)
        at io.smallrye.jwt.auth.principal.DefaultJWTTokenParser.parse(DefaultJWTTokenParser.java:56)
        at io.smallrye.jwt.auth.principal.DefaultJWTCallerPrincipalFactory.parse(DefaultJWTCallerPrincipalFactory.java:31)
        at io.smallrye.jwt.auth.principal.DefaultJWTParser.parse(DefaultJWTParser.java:60)
        at io.smallrye.jwt.auth.principal.DefaultJWTParser_Subclass.parse$$superaccessor9(DefaultJWTParser_Subclass.zig:1575)
        at io.smallrye.jwt.auth.principal.DefaultJWTParser_Subclass$$function$$9.apply(DefaultJWTParser_Subclass$$function$$9.zig:33)
        at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:54)
        at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.proceed(InvocationInterceptor.java:63)
        at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.monitor(InvocationInterceptor.java:51)
        at io.quarkus.arc.runtime.devconsole.InvocationInterceptor_Bean.intercept(InvocationInterceptor_Bean.zig:521)
        at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41)
        at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41)
        at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32)
        at io.smallrye.jwt.auth.principal.DefaultJWTParser_Subclass.parse(DefaultJWTParser_Subclass.zig:1523)
        at io.smallrye.jwt.auth.principal.DefaultJWTParser_ClientProxy.parse(DefaultJWTParser_ClientProxy.zig:368)
        at io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator$1.accept(MpJwtValidator.java:53)
        at io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator$1.accept(MpJwtValidator.java:49)
        at io.smallrye.context.impl.wrappers.SlowContextualConsumer.accept(SlowContextualConsumer.java:21)
        at io.smallrye.mutiny.operators.uni.builders.UniCreateWithEmitter.subscribe(UniCreateWithEmitter.java:22)
        at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
        at io.smallrye.mutiny.operators.uni.UniMemoizeOp.subscribe(UniMemoizeOp.java:76)
        at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
        at io.smallrye.mutiny.groups.UniSubscribe.withSubscriber(UniSubscribe.java:50)
        at io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder$2.handle(HttpSecurityRecorder.java:104)
        at io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder$2.handle(HttpSecurityRecorder.java:51)
        at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1038)
        at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:137)
        at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:132)
        at io.quarkus.micrometer.runtime.binder.vertx.VertxMeterFilter.handle(VertxMeterFilter.java:19)
        at io.quarkus.micrometer.runtime.binder.vertx.VertxMeterFilter.handle(VertxMeterFilter.java:14)
        at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1038)
        at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:137)
        at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:132)
        at io.quarkus.vertx.http.runtime.devmode.VertxHttpHotReplacementSetup$3.handle(VertxHttpHotReplacementSetup.java:88)
        at io.quarkus.vertx.http.runtime.devmode.VertxHttpHotReplacementSetup$3.handle(VertxHttpHotReplacementSetup.java:77)
        at io.vertx.core.impl.ContextImpl.lambda$null$0(ContextImpl.java:327)
        at io.vertx.core.impl.ContextImpl$$Lambda$766/0x00000008005f8840.handle(UnkNown Source)
        at io.vertx.core.impl.ContextImpl.executeTask(ContextImpl.java:366)
        at io.vertx.core.impl.EventLoopContext.lambda$executeAsync$0(EventLoopContext.java:38)
        at io.vertx.core.impl.EventLoopContext$$Lambda$713/0x0000000800588840.run(UnkNown Source)
        at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
        at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500)
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base@11.0.2/java.lang.Thread.run(Thread.java:834)

因此,我希望 JWKS 刷新作为响应式请求之外的单独计划进程发生。我在 Quarkus 中没有找到对此的支持

目前我正计划创建一个计划任务来调用 JWKS URL,提取公钥并将其保存为文件。然后我可以将公钥位置指向该文件

编辑

尝试过,但Quarkus 缓存了公钥文件,因此刷新它没有帮助。

截至目前,问题已消失,并且在问题未发生之前的某个时间点也已消失。 Quarkus 是否决定在响应式 REST 资源请求期间刷新 JWKS 似乎取决于运气。

我预计问题会再次出现,但让我们看看。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。