You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Quarkus集成Keycloak OIDC时如何基于mTLS主体授权服务调用

零侵入落地方案(无需修改api-service业务客户端代码)

核心思路

你之前尝试的Keycloak mTLS能力是基于RFC8705的OAuth2客户端证书认证方案,该方案要求调用方客户端主动在token请求阶段携带mTLS证书,必须修改客户端对接逻辑,确实不适合你的场景。
可行方案是把token获取、注入的逻辑从api-service业务代码里剥离,放到透明的基础设施层/请求拦截层,复用你已经解析完成的mTLS principal身份信息,自动完成Keycloak令牌的申请、注入,全程对api-service业务逻辑无感知,repository侧直接复用现有Keycloak OIDC的授权校验能力即可,不需要额外重构。

repository(Quarkus服务端)配置

原有Keycloak OIDC保护逻辑完全保留,只需要补充2项配置:

  • 保留现有quarkus-oidc扩展的基础配置,正常校验Keycloak签发的JWT令牌签名、有效期,原有接口上的@RolesAllowed、@Authenticated等权限注解不需要做任何修改
  • 在Keycloak中给对应客户端配置自定义令牌声明映射:把api-service侧透传的mTLS principal信息(比如客户端证书CN、SAN扩展值)写入JWT的自定义claims,repository端直接从JWT上下文读取主体信息做细粒度授权即可,不需要重复做mTLS证书解析

注意:mTLS的信任边界收敛在api-service的入口层即可,repository到api-service的内网链路不需要重复配置mTLS校验,repository只信任Keycloak签发的合法令牌,减少冗余校验逻辑。

api-service侧实现(零业务代码改动)

根据你的部署形态二选一即可,两种方案都不需要修改现有api-service对接repository的业务代码:

  • 边车代理模式(推荐,完全零代码)
    在api-service同Pod/同主机旁部署轻量反向代理(Nginx、Envoy均可),所有发往repository的出站请求统一经过代理转发:
    1. 代理层先承接入口mTLS流量,完成客户端证书校验、principal解析(这步你已经实现)
    2. 代理层内置token缓存逻辑:首次识别到新的mTLS principal时,以client_credentials模式向Keycloak申请对应权限的访问令牌,缓存到令牌过期前1分钟,后续同主体请求直接复用缓存令牌
    3. 代理自动把令牌注入到出站请求的Authorization: Bearer <token>请求头,再转发给repository,api-service业务代码完全感知不到该流程
      代理层申请令牌的示例请求配置:
    POST https://<keycloak-internal-address>/realms/<your-realm>/protocol/openid-connect/token
    Content-Type: application/x-www-form-urlencoded
    
    grant_type=client_credentials&
    client_id=api-service&
    client_secret=<api-service-confidential-client-secret>&
    scope=repository:invoke&
    claims={"mtls_principal":"<parsed-cert-principal-value>"}
    
  • Quarkus REST客户端拦截器模式(api-service为Quarkus应用时可选)
    如果api-service本身基于Quarkus开发,只需要新增一个全局REST客户端拦截器,不需要修改任何业务调用代码:
    1. 拦截器优先级设为最高,拦截所有发往repository的请求
    2. 拦截器直接从请求上下文中读取你已经解析完成的mTLS principal,通过Quarkus内置的OidcClient获取Keycloak令牌(同样做本地缓存避免重复请求Keycloak)
    3. 自动把令牌注入到请求头后放行
      示例拦截器代码:
    @Provider
    @ClientInterceptor
    public class MtlsOidcTokenInjectInterceptor implements ClientRequestFilter {
        @Inject
        OidcClient oidcClient;
        @Inject
        // 你现有逻辑中存储mTLS解析结果的持有器
        MtlsPrincipalContext principalContext;
        // 本地token缓存,可使用Caffeine等轻量缓存实现
        LoadingCache<String, String> tokenCache = CacheBuilder.newBuilder()
                .expireAfterWrite(4, TimeUnit.MINUTES)
                .build(CacheLoader.from(principal -> {
                    TokenResponse tokenResp = oidcClient.createTokens(Map.of("mtls_principal", principal));
                    return tokenResp.getAccessToken();
                }));
    
        @Override
        public void filter(ClientRequestContext requestContext) {
            String currentPrincipal = principalContext.getCurrentCertPrincipal();
            String accessToken = tokenCache.getUnchecked(currentPrincipal);
            requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken);
        }
    }
    

授权校验逻辑

配置完成后所有授权逻辑完全复用现有Keycloak+Quarkus的能力栈,不需要额外开发:

  • 在Keycloak侧给不同mTLS principal对应的身份绑定角色、资源权限策略
  • repository侧直接通过JWT令牌中的claims获取主体信息,用原有注解做接口级权限控制、细粒度资源授权即可
  • api-service侧业务代码全程不需要修改对接逻辑,所有认证相关逻辑都在非业务层透明处理

内容的提问来源于stack exchange,提问作者Jakub Grabowski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 03:24:25