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

如何在服务B中验证从服务A获取的Keycloak Token?报错排查

问题背景

我部署了服务A与服务B,其中Keycloak与服务A运行在同一容器内。

服务A配置

[app]
PageSize = 10
JwtSecret = 233
PrefixUrl = http://127.0.0.1:8000

[sso]
Host = http://127.0.0.1:8080
AdminLogin = some_admin
AdminPassword = some_password
Realm = master
ClientID = my_client
ClientSecret = XXX

服务A已配置中间件验证Keycloak颁发的JWT,功能正常。

服务B配置

[app]
PageSize = 10
JwtSecret = 233
PrefixUrl = http://127.0.0.1:8002

[sso]
Host = http://172.18.0.1:8080
AdminLogin = some_admin
AdminPassword = some_password
Realm = master
ClientID = my_client
ClientSecret = XXX

由于Keycloak不在服务B所在容器,服务B用172.18.0.1:8080访问Keycloak。将服务A获取的同一JWT放入请求头调用服务B时,Keycloak返回报错:

{
    "code": "ERROR_AUTH_CHECK_TOKEN_FAIL",
    "context": {
        "code": 401,
        "message": "401 Unauthorized: invalid_token: Token verification failed",
        "type": "unknown"
    }
}

疑问

  1. 是否是Keycloak检测到代理导致验证失败?
  2. 是否需要为两个服务分别配置Keycloak客户端?
  3. 若需要,如何在服务B中验证从服务A获取的JWT?

问题分析与解决方案

1. 代理检测是否是失败原因?

不是。Keycloak验证JWT时核心检查签名有效性、Token过期时间、iss(签发者)声明与当前Realm URL匹配性、aud(受众)声明是否包含当前客户端ID等。你的情况大概率是JWT中iss的值是http://127.0.0.1:8080,但服务B用http://172.18.0.1:8080访问Keycloak,两者不匹配导致签发者验证失败。

2. 是否需要分别配置客户端?

不是强制要求,但分客户端是更规范的实践:

  • 可独立控制两个服务的权限范围,避免权限过度授予
  • 便于审计各服务的Token使用日志
  • 后续调整单个服务的认证策略时不会影响另一服务

如果暂时不想拆分,也可复用同一客户端,但必须解决Realm URL匹配问题。

3. 验证失败的解决办法

方案一:统一Keycloak的访问地址(推荐)

修改Keycloak配置,让容器间使用统一的内部域名(比如http://keycloak:8080,依赖Docker DNS或自定义容器网络的域名解析),然后服务A和服务B的sso.Host都配置为该地址。这样JWT的iss声明会统一为这个域名,两个服务验证时URL一致,就不会出现不匹配问题。

方案二:复用同一客户端,调整服务B的验证逻辑

如果无法统一Keycloak地址,可调整服务B的验证逻辑:

  • 从Keycloak的http://172.18.0.1:8080/realms/master/protocol/openid-connect/certs端点获取Realm公钥
  • 手动验证JWT的签名、过期时间等核心字段,忽略iss声明的URL匹配(不推荐,会降低安全性)
  • 或者在验证时,将iss的预期值硬编码为http://127.0.0.1:8080,而非服务B配置的sso.Host

方案三:为服务B创建独立客户端(规范实践)

  1. 在Keycloak的master Realm中创建新客户端my_client_b:
    • 访问类型选择confidential(后端服务推荐)
    • 根URL填写服务B的地址http://127.0.0.1:8002
    • 保存后获取新的ClientSecret
  2. 更新服务B的配置:
    [sso]
    Host = http://172.18.0.1:8080
    AdminLogin = some_admin
    AdminPassword = some_password
    Realm = master
    ClientID = my_client_b
    ClientSecret = NEW_CLIENT_SECRET
    
  3. 解决跨客户端Token验证问题:
    • 方法一:服务A获取Token时,请求参数中指定audience=my_client,my_client_b,让Token的aud声明包含两个客户端ID
    • 方法二:在Keycloak的my_client客户端配置中,添加my_client_b到允许的受众列表
    • 方法三:服务B调用Keycloak的Token introspection端点http://172.18.0.1:8080/realms/master/protocol/openid-connect/token/introspect,用自身客户端凭证验证服务A的Token,这种方式Keycloak会忽略aud匹配,只要Token有效未过期即返回成功。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 00:06:24