容器化Spring Boot微服务网关Keycloak iss声明无效401错误求助
问题分析
你遇到的401错误确实是JWT的iss声明不匹配导致的:
- 当你通过
http://localhost:8890获取token时,Keycloak会将外部访问地址作为iss写入token,即http://localhost:8890/realms/my-realm - 但API网关在容器内部配置的issuer-uri是
http://keycloak:8080/realms/my-realm,Spring Security OAuth2资源服务器会严格校验JWT的iss字段,两者不匹配就会返回401
解决方案
要解决这个问题,需要让Keycloak生成的JWT中的iss字段和网关配置的issuer-uri保持一致,具体可以通过配置Keycloak的hostname参数实现:
- 修改Keycloak的环境变量配置
在你的keycloak.dev.env文件中添加以下配置:
KC_HOSTNAME=keycloak KC_HOSTNAME_PORT=8080 KC_HOSTNAME_STRICT=false KC_HOSTNAME_STRICT_HTTPS=false
KC_HOSTNAME:指定Keycloak的内部服务名(对应docker-compose中的服务名keycloak),让Keycloak生成的JWT中iss字段使用这个地址KC_HOSTNAME_PORT:指定内部通信端口(Keycloak容器内部的8080端口)KC_HOSTNAME_STRICT=false:允许外部通过localhost:8890访问Keycloak,但仍使用配置的hostname作为iss字段KC_HOSTNAME_STRICT_HTTPS=false:开发环境下禁用HTTPS严格模式
- 重启容器
执行以下命令重启Keycloak和API网关容器:
docker-compose down && docker-compose up -d
- 重新获取token并验证
通过http://localhost:8890/realms/my-realm/protocol/openid-connect/token重新获取token,此时token中的iss字段会变为http://keycloak:8080/realms/my-realm,和网关配置的issuer-uri一致,再调用接口就不会出现401错误了。
备选方案(不推荐)
如果不想修改Keycloak配置,也可以修改API网关的issuer-uri为外部访问地址,但需要注意网关在容器内部需要能访问到这个地址,此时需要将网关的issuer-uri改为http://host.docker.internal:8890/realms/my-realm(针对Docker Desktop),但这种方式依赖宿主机的网络配置,不如第一种方案稳定。
内容的提问来源于stack exchange,提问作者Shanka Somasiri
相关产品推荐
相关产品推荐

