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

如何在OpenFeign中复用用户会话的Access Token调用微服务?

统一复用用户Access Token实现Feign跨服务调用

核心前提

要复用用户到后端的Access Token调用微服务,首先得确保该Token具备访问下游微服务的权限:

  • 在Keycloak中,给用户认证用的客户端(authorization_code模式的那个)添加下游微服务客户端的角色,或者配置对应的资源权限/scope,让用户的Access Token包含调用微服务的权限声明。
  • 下游微服务需配置为Resource Server,校验Token的issuer、audience等参数需与用户Access Token匹配。

实现步骤

1. 实现Feign请求拦截器,从Security上下文提取用户Access Token

弃用之前基于client_credentials的AuthorizedClientServiceOAuth2AuthorizedClientManager,改为直接从当前请求的Security上下文获取用户的Access Token,并自动注入到Feign请求头中:

@Component
public class UserAccessTokenFeignInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        // 仅在存在用户OAuth2认证上下文时注入Token
        if (auth instanceof OAuth2AuthenticationToken) {
            OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) auth;
            OAuth2AccessToken accessToken = oauthToken.getPrincipal().getAccessToken();
            template.header("Authorization", "Bearer " + accessToken.getTokenValue());
        }
    }
}

2. 配置Spring Security自动刷新Token

Spring Security OAuth2框架本身支持用Refresh Token自动刷新过期的Access Token,只需确保你的Security配置正确开启相关支持,刷新后的Token会自动更新到Security上下文,Feign调用就能直接复用新Token:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
            // 开启OAuth2登录,确保Refresh Token被正确存储
            .oauth2Login(oauth2 -> oauth2
                .tokenEndpoint(token -> token
                    .accessTokenResponseClient(accessTokenResponseClient())
                )
            )
            // 配置资源服务器,支持JWT Token校验
            .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
        
        return http.build();
    }

    // 配置支持Refresh Token的Token响应客户端
    @Bean
    public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient() {
        DefaultAuthorizationCodeTokenResponseClient client = new DefaultAuthorizationCodeTokenResponseClient();
        // 可根据需求自定义ClientRegistration、RestTemplate等配置
        return client;
    }
}

3. 处理异步调用场景(可选)

如果你的Feign调用是在异步线程中执行,需要确保Security上下文能传递到异步线程,否则会无法获取用户Token:

  • 全局配置线程上下文继承:
@Configuration
public class AsyncConfig implements AsyncConfigurer {
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setTaskDecorator(runnable -> {
            SecurityContext context = SecurityContextHolder.getContext();
            return () -> {
                try {
                    SecurityContextHolder.setContext(context);
                    runnable.run();
                } finally {
                    SecurityContextHolder.clearContext();
                }
            };
        });
        executor.initialize();
        return executor;
    }
}

关键注意事项

  • 下游微服务的Resource Server配置必须信任用户Access Token的issuer(即你的Keycloak实例),并且Token的aud(受众)或scope包含微服务的访问权限。
  • 用户的Refresh Token有效期需合理配置,确保在用户会话期间能自动刷新Access Token。
  • 若遇到Token刷新失败(比如Refresh Token过期),需在业务代码中处理对应的异常,引导用户重新登录。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.11 10:04:53