Quarkus/Vert.x HttpAuthenticationMechanism获取ResourceInfo方法
Quarkus RESTEasy Reactive 中 HttpAuthenticationMechanism 获取ResourceInfo实现方案
以下方案可直接解决RESTEasy Reactive下HttpAuthenticationMechanism无法获取ResourceInfo的问题,相关问题本质是请求处理链路顺序、Bean作用域不匹配导致的,不需要绕路加过滤器:
核心实现逻辑
RESTEasy Reactive的路由匹配动作在安全认证拦截执行前已经完成,匹配到的资源类、方法元数据会直接挂载到当前请求的RoutingContext属性中,直接在authenticate方法内读取即可,完全不需要依赖请求作用域注入、不需要等待ContainerRequestFilter执行。
代码实现
import io.quarkus.security.identity.IdentityProviderManager; import io.quarkus.security.identity.SecurityIdentity; import io.quarkus.vertx.http.runtime.security.HttpAuthenticationMechanism; import io.smallrye.mutiny.Uni; import io.vertx.ext.web.RoutingContext; import jakarta.annotation.Priority; import jakarta.enterprise.context.ApplicationScoped; import jakarta.ws.rs.Priorities; import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext; import org.jboss.resteasy.reactive.server.jaxrs.ResourceInfoImpl; import jakarta.ws.rs.container.ResourceInfo; import java.lang.reflect.Method; import java.util.Optional; @ApplicationScoped @Priority(Priorities.AUTHENTICATION) public class RoutingAuthMechanism implements HttpAuthenticationMechanism { final AuthConfigMapping authConfigMapping; public RoutingAuthMechanism(AuthConfigMapping authConfigMapping) { this.authConfigMapping = authConfigMapping; } @Override public Uni<SecurityIdentity> authenticate(RoutingContext context, IdentityProviderManager identityProviderManager) { // 从当前请求上下文取出RESTEasy Reactive提前完成匹配的资源元信息 ResteasyReactiveRequestContext rrContext = context.get(ResteasyReactiveRequestContext.class.getName()); // 未匹配到JAX-RS资源的静态请求、404请求,直接返回空走默认逻辑 if (rrContext == null) { return Uni.createFrom().optional(Optional.empty()); } // 构造标准ResourceInfo实例 Class<?> resourceClass = rrContext.getTarget().getResourceClass(); Method resourceMethod = rrContext.getTarget().getJavaMethod(); ResourceInfo resourceInfo = new ResourceInfoImpl(resourceClass, resourceMethod); // 读取@Authorization注解,优先取方法上的注解,不存在则取类上的注解 Authorization authAnnotation = resourceInfo.getResourceMethod().getAnnotation(Authorization.class); if (authAnnotation == null) { authAnnotation = resourceInfo.getResourceClass().getAnnotation(Authorization.class); } // 未标注注解的资源走默认认证逻辑 if (authAnnotation == null) { return Uni.createFrom().optional(Optional.empty()); } String authKey = authAnnotation.value(); AuthConfigMapping.AuthConfig authConfig = authConfigMapping.auth().get(authKey); if (authConfig == null) { throw new RuntimeException("未找到认证配置:" + authKey); } // 根据authConfig.type()判断认证类型,分别调用JWT、OIDC等对应认证逻辑即可 return switch (authConfig.type()) { case "jwt" -> doJwtAuth(context, identityProviderManager, authConfig); case "oidc" -> doOidcAuth(context, identityProviderManager, authConfig); default -> Uni.createFrom().optional(Optional.empty()); }; } private Uni<SecurityIdentity> doJwtAuth(RoutingContext context, IdentityProviderManager manager, AuthConfigMapping.AuthConfig config) { // 实现JWT认证逻辑 return Uni.createFrom().optional(Optional.empty()); } private Uni<SecurityIdentity> doOidcAuth(RoutingContext context, IdentityProviderManager manager, AuthConfigMapping.AuthConfig config) { // 实现OIDC认证逻辑 return Uni.createFrom().optional(Optional.empty()); } }
相关配套代码
自定义Authorization注解
import java.lang.annotation.*; @Inherited @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Authorization { // 对应配置中的认证项key String value(); }
注解支持同时标注在类、方法上,方法上的注解优先级高于类上的。
配置映射类
直接映射配置文件中myframework.auth下的所有配置项,不需要手动逐行读取配置:
import io.smallrye.config.ConfigMapping; import java.util.Map; import java.util.Optional; @ConfigMapping(prefix = "myframework") public interface AuthConfigMapping { Map<String, AuthConfig> auth(); interface AuthConfig { String type(); Optional<String> issuer(); Optional<String> audience(); Optional<String> authServerUrl(); } }
常见失效方案的原因说明
- 直接注入
ResourceInfo失效:ResourceInfo是请求作用域对象,HttpAuthenticationMechanism是应用作用域单例Bean,直接注入会拿到未绑定当前请求上下文的代理对象,调用时会抛出上下文不存在的异常。 - 从
RoutingContext未找到资源信息:之前查找的属性键不适用于RESTEasy Reactive,RESTEasy Reactive的请求上下文固定以类全限定名作为key存在RoutingContext中。 ContainerRequestFilter执行时机晚于认证:RESTEasy Reactive默认的请求过滤器优先级低于安全拦截优先级,即使给过滤器调整优先级提前执行,也只是多做一次上下文属性传递,不如直接在认证逻辑中读取元数据简洁。
该方案兼容Quarkus 2.13+、3.x全系列使用RESTEasy Reactive的版本,不存在执行时机、作用域不匹配问题。
内容的提问来源于stack exchange,提问作者Sof42lxca
相关产品推荐
相关产品推荐

