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

微服务间使用Keycloak Token通信失败,如何解决?

问题根因
  1. 网关当前仅配置了oauth2Login(),这是为浏览器端用户登录设计的认证流程,未配置资源服务器逻辑来验证Bearer Token,导致微服务携带Token调用时无法通过认证。
  2. 你传递的是ID Token,ID Token主要用于用户身份认证,而非服务间资源访问,应该使用Access Token。
  3. 微服务调用时的Authorization头格式可能不规范,正确格式应为Bearer <token>。
解决方案

1. 改造网关安全配置,添加资源服务器支持

修改SecurityConfig,加入oauth2ResourceServer()配置,让网关能够验证Bearer Token:

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http,
                                                            ReactiveClientRegistrationRepository clientRegistrationRepository) {
        // 配置OIDC登录(浏览器端)
        http.authorizeExchange()
                .pathMatchers("/app/").authenticated()
                .and().cors()
                .and().oauth2Login();

        // 配置资源服务器,验证Bearer Token(服务间调用)
        http.oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.jwtDecoder(jwtDecoder())));

        // 配置OIDC登出
        http.logout(logout -> logout.logoutSuccessHandler(
                new OidcClientInitiatedServerLogoutSuccessHandler(clientRegistrationRepository)));

        // 所有请求需要认证
        http.authorizeExchange().anyExchange().authenticated();

        // 允许同源iframe
        http.headers().frameOptions().mode(XFrameOptionsServerHttpHeadersWriter.Mode.SAMEORIGIN);

        // 禁用CSRF
        http.csrf().disable();
        return http.build();
    }

    // 配置JWT解码器,从Keycloak获取公钥验证Token
    @Bean
    public JwtDecoder jwtDecoder() {
        return NimbusJwtDecoder.withIssuerLocation("http://localhost:8280/auth/realms/Default")
                .build();
    }
}

2. 替换Token类型:使用Access Token而非ID Token

修改网关控制器代码,获取Access Token传递给微服务:

@RestController
@RequestMapping("/aiv")
public class UserController {

    @Autowired
    DataSource dataSource;

    @PostMapping(path = "/authenticate", produces = MediaType.APPLICATION_JSON_VALUE)
    public String getAuth(@RequestBody Map<String, Object> data, Authentication authentication) {
        // 获取Access Token(而非ID Token)
        OAuth2AuthenticationToken oAuth2Token = (OAuth2AuthenticationToken) authentication;
        String accessToken = oAuth2Token.getPrincipal().getAttribute("access_token");
        // 补全Bearer前缀
        data.put("Authorization", "Bearer " + accessToken);
        
        String responseData = new DefaultAuthenticateImpl().authenticateByPassword(data, dataSource);
        return responseData;
    }
}

3. 确保微服务调用时的Authorization头格式正确

检查微服务的调用代码,确保Authorization头符合Bearer <token>格式(网关传递时已处理,若单独传入Token需补全前缀):

public String getRequest(String stUrl, Map<String, Object> data) {
    try {
        HttpClient httpclient = HttpClients.createDefault();
        HttpGet httpget = new HttpGet(stUrl);

        // 遍历添加头信息
        for (Map.Entry<String, Object> entry : data.entrySet()) {
            httpget.addHeader(entry.getKey(), entry.getValue().toString());
        }

        // 若直接传入Token,需补全格式
        // httpget.setHeader("Authorization", "Bearer " + <<AuthToken>>);

        ResponseHandler<String> responseHandler = new BasicResponseHandler();
        String resp = httpclient.execute(httpget, responseHandler);
        return resp;
    } catch (Exception e) {
        e.printStackTrace(); // 建议打印异常便于排查
        return null;
    }
}

4. 验证Keycloak配置

  • 确保Keycloak客户端的Access Token Lifespan设置合理,避免Token提前过期。
  • 客户端的Access Type需设置为confidential(你的配置已使用client-secret,此环节无需调整)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 23:15:27