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

Keycloak与Spring微服务Docker部署的令牌验证问题

解决Docker Compose下Keycloak内外Issuer不匹配的问题

问题核心

外部客户端通过公网IP获取的令牌,其Issuer是http://1.2.3.4:8080/realms/my-realm,但Docker内部Spring服务配置的验证Issuer是http://keycloak:8080/realms/my-realm,两者不匹配导致验证失败。下面提供三种可行解决方案:

方案1:统一Issuer为公网地址(推荐)

直接将Spring服务的验证配置改为公网Issuer:

spring.security.oauth2.resourceserver.jwt.issuer-uri=http://1.2.3.4:8080/realms/my-realm

同时确保Docker容器能访问该公网IP对应的Keycloak服务:

  • 如果Keycloak和Spring服务在同一主机,可在docker-compose.yml中给Spring服务添加extra_hosts映射,让公网IP指向Keycloak容器的内部地址:
    services:
      spring-service:
        extra_hosts:
          - "1.2.3.4:keycloak"
    

这样Spring服务会用公网Issuer验证令牌,和令牌中的Issuer完全匹配,同时通过hosts映射内部访问Keycloak,避免走公网流量。

方案2:让Spring接受多个Issuer

如果不想修改现有配置,可自定义JwtDecoder,允许Spring同时验证两个Issuer的令牌:

import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtValidators;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.context.annotation.Bean;

@Bean
public JwtDecoder jwtDecoder() {
    NimbusJwtDecoder decoder = NimbusJwtDecoder.withIssuerLocation("http://keycloak:8080/realms/my-realm").build();
    decoder.setJwtValidator(JwtValidators.createDefaultWithIssuers(
        "http://keycloak:8080/realms/my-realm",
        "http://1.2.3.4:8080/realms/my-realm"
    ));
    return decoder;
}

此方案适合临时测试或过渡场景,不推荐生产环境使用,因为会增加令牌验证的复杂度。

方案3:用反向代理统一域名(生产环境首选)

生产环境建议使用域名替代IP,通过反向代理实现内外访问的统一Issuer:

  1. 配置域名(如auth.example.com)指向你的服务器公网IP
  2. 在Docker Compose中部署Nginx作为反向代理,将域名请求转发到Keycloak容器:
    services:
      nginx:
        image: nginx:alpine
        ports:
          - "80:80"
          - "443:443"
        volumes:
          - ./nginx.conf:/etc/nginx/nginx.conf
        depends_on:
          - keycloak
      keycloak:
        image: quay.io/keycloak/keycloak:latest
        environment:
          - KC_HOSTNAME_URL=http://auth.example.com
          - KC_HOSTNAME_ADMIN_URL=http://auth.example.com
          - KC_HTTP_ENABLED=true
        networks:
          - app-network
    
  3. Nginx配置示例(nginx.conf):
    server {
        listen 80;
        server_name auth.example.com;
    
        location / {
            proxy_pass http://keycloak:8080;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
    
  4. 修改Spring服务和外部客户端的配置,统一使用域名作为Issuer:
    # Spring服务配置
    spring.security.oauth2.resourceserver.jwt.issuer-uri=http://auth.example.com/realms/my-realm
    
    // 外部客户端(oidc-react)配置
    const config = {
      authority: "http://auth.example.com/realms/my-realm",
      // 其他配置...
    };
    

这种方式实现了Issuer完全统一,同时兼顾内外访问,是生产环境的标准做法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 06:16:07