You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Docker内部容器部署Keycloak时令牌签发者不匹配及Spring后端连接异常问题咨询

解决Keycloak令牌签发者不匹配的问题

我之前也碰到过几乎一模一样的场景:本地跑完全正常,到了测试环境用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

火山引擎 最新活动