Spring WebClient每次请求资源服务器重复获取访问令牌问题排查
解决OAuth2 Client Credentials模式下访问令牌重复获取问题
你的配置存在三处核心问题,导致每次请求都重新获取令牌:
- 冗余的oauth2Login配置:你使用的是Client Credentials模式,不需要授权码登录流程,
oauth2Login()配置完全多余,还会干扰授权客户端的管理逻辑。 - 手动传递授权客户端实例:Controller中通过
@RegisteredOAuth2AuthorizedClient获取的实例是每次请求新生成的,没有复用缓存的令牌。 - 未配置令牌缓存机制:默认的内存存储不会自动缓存Client Credentials模式的令牌,需要显式配置授权客户端管理器来处理缓存和自动刷新。
优化步骤
1. 修正Security配置,启用正确的OAuth2客户端支持
移除无用的oauth2Login(),添加Client Credentials模式专属的授权客户端管理器,负责令牌的缓存和自动刷新:
@Configuration(proxyBeanMethods = false) @EnableWebFluxSecurity public class SecurityConfig { @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http.authorizeExchange(exchange -> exchange.anyExchange().permitAll()) .oauth2Client(withDefaults()); // 启用OAuth2客户端核心支持 return http.build(); } @Bean ReactiveOAuth2AuthorizedClientManager authorizedClientManager( ReactiveClientRegistrationRepository clientRegistrationRepository, ReactiveOAuth2AuthorizedClientService authorizedClientService) { // 配置Client Credentials模式的授权提供者 ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder.builder() .clientCredentials() .build(); // 使用授权客户端服务来管理和缓存令牌 AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager = new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager( clientRegistrationRepository, authorizedClientService); authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider); return authorizedClientManager; } }
2. 重构WebClient配置,使用授权客户端管理器
让WebClient通过授权客户端管理器自动处理令牌的获取、缓存和刷新,不再依赖手动传递实例:
@Configuration public class WebClientConfig { @Bean WebClient getClient(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) { ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager); oauth.setDefaultClientRegistrationId("salesforce"); return WebClient.builder() .filter(oauth) .build(); } }
3. 简化Controller逻辑
移除手动传递授权客户端的代码,让WebClient自动完成令牌注入:
@RestController public class SalesforceController { private final WebClient webClient; public SalesforceController(WebClient webClient) { this.webClient = webClient; } @GetMapping(value="/order", produces="application/json") Mono<String> getOrder() { return this.webClient .get() .uri("https://my.service.com/Order/1") .retrieve() .bodyToMono(String.class) .timeout(Duration.ofSeconds(5)); } }
优化后效果
- 令牌会被
ReactiveOAuth2AuthorizedClientService自动缓存,有效期内所有请求复用同一令牌 - 令牌过期时会自动触发刷新流程,无需手动干预
- 配置符合Spring Security OAuth2 Client Credentials模式的最佳实践,冗余代码全部清除
内容的提问来源于stack exchange,提问作者Dale Ogilvie
相关产品推荐
相关产品推荐

