Keycloak与Spring Boot集成:请求OpenID配置时连接被拒
问题:Docker部署的Spring Boot应用无法连接同主机的Keycloak
环境配置
Keycloak Docker Compose 配置
keycloak: image: quay.io/keycloak/keycloak:20.0.1 container_name: keycloak command: - start-dev labels: - 'traefik.enable=true' - 'traefik.http.routers.keycloak.rule=Host(`myhostname.com`) && PathPrefix(`/auth`)' - 'traefik.http.routers.keycloak.entrypoints=https' - 'traefik.http.routers.keycloak.tls=true' - 'traefik.http.routers.keycloak.tls.certresolver=letsencrypt' environment: KC_DB: mariadb KC_DB_URL: ${KC_DB_URL} KC_DB_USERNAME: ${MARIADB_USERNAME} KC_DB_PASSWORD: ${MARIADB_PASSWORD} KEYCLOAK_ADMIN: ${KEYCLOAK_SUPER_ADMIN_USER} KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_SUPER_ADMIN_PASS} KC_PROXY: ${KC_PROXY:-passthrough} KC_HTTP_RELATIVE_PATH: ${KC_HTTP_RELATIVE_PATH:-/auth} volumes: - ${PWD}/docker/keycloak:/opt/keycloak/data/import ports: - ${KEYCLOAK_PORT:-8087}:8080 depends_on: - db-keycloak networks: net:
Keycloak通过Traefik反向代理暴露在https://myhostname.com/auth路径下。
Spring Boot应用Docker Compose配置
app: container_name: app image: ghcr.io/repo/image:tag environment: MARIADB_HOST: ${MARIADB_HOST} MARIADB_PORT: ${MARIADB_PORT} MARIADB_DATABASE: ${MARIADB_DATABASE} MARIADB_USERNAME: ${MARIADB_USERNAME} MARIADB_PASSWORD: ${MARIADB_PASSWORD} KEYCLOAK_CLIENT_ID: ${KEYCLOAK_CLIENT_ID} KC_HOSTNAME_URL: ${KC_HOSTNAME_URL} KEYCLOAK_REALM_NAME: ${KEYCLOAK_REALM_NAME} ports: - ${APP_PORT}:8080 restart: always labels: - 'traefik.enable=true' - 'traefik.http.routers.app.rule=Host(`myhostname.com`) && PathPrefix(`/app`)' - 'traefik.http.routers.app.entrypoints=https' - 'traefik.http.routers.app.tls=true' - 'traefik.http.routers.app.tls.certresolver=letsencrypt' depends_on: - db networks: - net
Spring Boot应用通过Traefik暴露在https://myhostname.com/app路径下。
错误信息
应用启动时连接Keycloak失败,报错:
Caused by: org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://myhostname.com/auth/realms/realm/.well-known/openid-configuration": Connection refused
Spring Boot配置文件
application.yaml
spring: security: oauth2: client: registration: keycloak: client-id: ${KEYCLOAK_CLIENT_ID} scope: openid authorization-grant-type: authorization_code provider: keycloak: issuer-uri: ${KC_HOSTNAME_URL}/realms/${KEYCLOAK_REALM_NAME} user-name-attribute: preferred_username resourceserver: jwt: issuer-uri: ${KC_HOSTNAME_URL}/realms/${KEYCLOAK_REALM_NAME}
SecurityConfig.java
@Configuration @EnableWebSecurity class SecurityConfig { public static final String USER = "user"; private final KeycloakLogoutHandler keycloakLogoutHandler; SecurityConfig(KeycloakLogoutHandler keycloakLogoutHandler) { this.keycloakLogoutHandler = keycloakLogoutHandler; } @Bean protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl()); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests() .anyRequest().authenticated(); http.oauth2Login() .and() .logout() .addLogoutHandler(keycloakLogoutHandler) .logoutSuccessUrl("/"); http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); return http.build(); } }
已尝试的方案
- 设置Keycloak客户端的
Web Origins: *,无效 - 将
KC_HOSTNAME_URL设置为http://keycloak:8080/auth,应用能连接Keycloak,但前端授权功能无法正常工作
解决方案
1. 区分内部/外部访问地址
容器间通信使用内部地址,前端跳转使用外部地址,避免连接拒绝问题:
- 修改Spring Boot的Docker Compose环境变量:
environment: KEYCLOAK_INTERNAL_URL: http://keycloak:8080/auth KEYCLOAK_EXTERNAL_URL: https://myhostname.com/auth
- 更新
application.yaml,分别配置客户端和资源服务器:
spring: security: oauth2: client: registration: keycloak: client-id: ${KEYCLOAK_CLIENT_ID} scope: openid authorization-grant-type: authorization_code provider: keycloak-external provider: keycloak-external: issuer-uri: ${KEYCLOAK_EXTERNAL_URL}/realms/${KEYCLOAK_REALM_NAME} user-name-attribute: preferred_username keycloak-internal: issuer-uri: ${KEYCLOAK_INTERNAL_URL}/realms/${KEYCLOAK_REALM_NAME} user-name-attribute: preferred_username resourceserver: jwt: issuer-uri: ${KEYCLOAK_INTERNAL_URL}/realms/${KEYCLOAK_REALM_NAME}
2. 修正Keycloak外部地址配置
Keycloak需要明确自身的外部访问地址,否则生成的授权链接会异常:
environment: KC_HOSTNAME: myhostname.com KC_HOSTNAME_PATH: /auth KC_HOSTNAME_STRICT_BACKCHANNEL: false
KC_HOSTNAME:设置为外部访问域名KC_HOSTNAME_PATH:对应Traefik代理的路径KC_HOSTNAME_STRICT_BACKCHANNEL:允许内部使用非外部地址访问
3. 验证Docker网络连通性
确认Traefik、Keycloak、Spring Boot应用都在同一个net网络中,进入Spring Boot容器执行以下命令测试连通性:
curl http://keycloak:8080/auth/realms/realm/.well-known/openid-configuration
4. 调整Traefik网络配置
如果Traefik未加入net网络,需要将其添加到该网络中;或者在Spring Boot容器的extra_hosts中添加域名映射:
extra_hosts: - "myhostname.com:traefik容器IP"
内容的提问来源于stack exchange,提问作者Spyros Mouchlianitis
相关产品推荐
相关产品推荐

