Quarkus如何从X-ARR-ClientCert请求头获取客户端证书完成身份认证
有成熟可行的实现方案,不需要从零搭建完整的认证逻辑,仅需基于Quarkus现有安全扩展做少量自定义开发即可满足需求。
核心实现逻辑
你不需要完全重写安全校验全链路,仅需实现自定义请求认证机制,配合Quarkus自带的TrustStore能力和身份提供器即可完成校验,具体步骤如下:
1. 前置Azure配置校验
首先确认Azure App Service侧配置符合要求:
- 将App Service的客户端证书模式设置为Required或Optional,确保负载均衡器会把客户端证书编码后写入
X-ARR-ClientCert请求头 - 无需担心请求头伪造风险:Azure App Service默认不会将外部请求携带的
X-ARR-ClientCert头透传给应用,仅会写入负载均衡器层面接收的客户端证书内容
2. 依赖引入
在项目的构建配置中引入Quarkus安全核心扩展,以Maven为例:
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-elytron-security</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-security</artifactId> </dependency>
3. 自定义请求认证机制
实现HttpAuthenticationMechanism接口,完成证书提取、校验逻辑,直接复用Quarkus已加载的TrustStore做校验:
@Alternative @Priority(1) @ApplicationScoped public class ArrClientCertAuthMechanism implements HttpAuthenticationMechanism { @Inject TrustManagerFactory trustManagerFactory; @Inject IdentityProviderManager identityProviderManager; @Override public Uni<SecurityIdentity> authenticate(RoutingContext context, IdentityProviderManager identityProviderManager) { String certHeader = context.request().getHeader("X-ARR-ClientCert"); // 无证书头直接跳过当前认证机制,由后续安全规则处理无权限请求 if (certHeader == null || certHeader.isBlank()) { return Uni.createFrom().nullItem(); } try { // 解码请求头内容生成X509证书实例 byte[] certBytes = Base64.getDecoder().decode(certHeader.trim()); CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); X509Certificate clientCert = (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(certBytes)); // 复用现有TrustStore做证书信任校验 X509TrustManager trustManager = (X509TrustManager) trustManagerFactory.getTrustManagers()[0]; trustManager.checkClientTrusted(new X509Certificate[]{clientCert}, "RSA"); // 复用Quarkus自带的X509身份提供器生成SecurityIdentity return identityProviderManager.authenticate(new X509AuthenticationCredential(clientCert)); } catch (Exception e) { return Uni.createFrom().failure(new AuthenticationFailedException("客户端证书校验不通过", e)); } } @Override public Uni<ChallengeData> getChallenge(RoutingContext context) { return Uni.createFrom().item(new ChallengeData(HttpResponseStatus.UNAUTHORIZED.code(), HttpHeaders.WWW_AUTHENTICATE, "ClientCertificate")); } @Override public Set<Class<? extends AuthenticationRequest>> getCredentialTypes() { return Collections.singleton(X509AuthenticationCredential.class); } }
4. TrustStore配置
直接在application.properties中配置你的信任库,Quarkus会自动加载并注入到上下文,无需自行读取解析:
# TrustStore配置 quarkus.tls.trust-store.type=JKS quarkus.tls.trust-store.path=classpath:your-truststore.jks quarkus.tls.trust-store.password=your-truststore-password
关于自定义Identity Provider的说明
- 如果你仅需要完成证书信任校验,默认用Quarkus自带的
X509IdentityProvider即可,无需额外自定义Identity Provider - 如果你需要从证书的扩展字段提取自定义身份标识、绑定业务角色、对接内部权限系统,再自行实现
IdentityProvider<X509AuthenticationCredential>接口,补充对应的身份映射逻辑即可
注意事项
- 生产环境需额外校验证书的有效期、吊销状态,避免过期证书通过校验
- 所有未携带合法证书的请求会被自动返回401状态码,也可结合Quarkus的
@RolesAllowed注解实现接口粒度的权限控制
内容的提问来源于stack exchange,提问作者SlowTree
相关产品推荐
相关产品推荐

