Docker内部容器部署Keycloak时令牌签发者不匹配及Spring后端连接异常问题咨询
我之前也碰到过几乎一模一样的场景:本地跑完全正常,到了测试环境用Docker部署后,后端总是报"Invalid token issuer"的401错误。折腾了好几天,终于把问题根源和解决方法理清楚了,分享给你:
问题根源拆解
你遇到的核心矛盾是:
- 前端访问Keycloak用的是测试服务器的外部IP,所以Keycloak生成的Token里的
iss(签发者)是这个外部地址 - 后端服务在Docker容器里,默认用内部容器名
http://keycloak:8080/auth/访问Keycloak,验证Token时就会期望iss是这个内部地址,两边不匹配直接打回401 - 要是把后端的
auth-server-url改成外部IP,又因为Docker容器网络的限制连不上Keycloak,陷入两难
一步步解决
1. 先让Keycloak生成正确的Issuer
首先得确保Keycloak生成的Token里的iss是前端访问的外部地址。这里要注意两个配置:
- 必须开
PROXY_ADDRESS_FORWARDING=true,让Keycloak识别反向代理或外部访问的地址 - 明确设置
FRONTEND_URL为你的外部访问地址(比如http://{our-test-server-IP}/auth/)
修改你的docker-compose.yml里的Keycloak配置,注意之前的-Dkeycloak.profile.feature.upload_scripts=enabled写法错了,要放到JAVA_OPTS里:
keycloak: image: jboss/keycloak:12.0.4 restart: on-failure environment: PROXY_ADDRESS_FORWARDING: "true" KEYCLOAK_USER: admin KEYCLOAK_PASSWORD: password KEYCLOAK_LOGLEVEL: DEBUG KEYCLOAK_IMPORT: /etc/settings/realm.json JAVA_OPTS: "-Dkeycloak.profile.feature.upload_scripts=enabled" TZ: Europe/Bucharest DB_VENDOR: POSTGRES DB_ADDR: db DB_DATABASE: user DB_SCHEMA: keycloak DB_USER: user DB_PASSWORD: user FRONTEND_URL: "http://{our-test-server-IP}/auth/" # 替换成你的外部地址 ports: - 8090:8080 volumes: - ./settings:/etc/settings depends_on: - db
要是你用Keycloak管理控制台,也可以进对应Realm的Settings -> Frontend URL填这个地址,保存后重启Keycloak。
2. 解决后端访问外部地址超时的问题
这一步是关键,要让Docker里的后端服务能访问到Keycloak的外部地址,推荐几个实用方法:
方法一:用Docker内置的主机映射(最省心)
在你的后端服务的docker-compose配置里加一行extra_hosts,直接映射到主机:
backend-service: # 替换成你的后端服务名称 # ... 其他配置 ... extra_hosts: - "host.docker.internal:host-gateway"
然后把后端的auth-server-url改成http://host.docker.internal/auth/(如果是直接用8090端口访问,就改成http://host.docker.internal:8090/auth/)。这个方法在Windows、Mac、Linux的Docker环境里基本都能用。
方法二:用Host网络模式(适合简单场景)
把Keycloak和后端服务的网络模式改成host,这样容器直接用主机的网络,就能访问外部IP了:
keycloak: # ... 其他配置 ... network_mode: host ports: - 8080:8080 # 注意端口映射要对应主机的端口,或者直接去掉端口映射 backend-service: # ... 其他配置 ... network_mode: host
不过这个方法在Windows和Mac的Docker Desktop里可能有兼容性问题,需要测试。
方法三:自定义Docker网络(适合复杂环境)
创建一个自定义的Docker网络,把所有服务都加进去,同时调整主机的防火墙规则,允许容器访问主机的端口。这个方法稍微复杂,但适合需要精细控制网络的场景。
3. 对齐后端的Keycloak配置
最后把后端的auth-server-url改成和你设置的FRONTEND_URL完全一致,这样验证Token时iss就会匹配:
keycloak: cors: true realm: Realm-Name resource: back-office auth-server-url: http://{our-test-server-IP}/auth/ # 和FRONTEND_URL保持一致 public-client: false credentials: secret: 8401b642-0ae9-4dc8-87a6-2f494b388a49 keycloak-client: id: bcc94ed5-0099-40e0-b460-572eba3f0214
4. 验证是否生效
重启Keycloak和后端服务后:
- 用前端登录拿Token,去jwt.io解析一下,看看
iss字段是不是你设置的外部地址 - 后端用这个Token调用接口,检查是不是返回200成功
要是还有问题,打开Keycloak的DEBUG日志(你已经设置了KEYCLOAK_LOGLEVEL: DEBUG),看看生成Token时的issuer是不是正确的,同时看后端的日志,排查验证时的具体错误。
内容的提问来源于stack exchange,提问作者Olaru Vlad




