Spring Boot应用通过代理调用Azure Entra获取OAuth2令牌失败
解决Spring Boot调用Azure Entra OAuth2 API的代理配置问题
核心问题分析
你遇到的Connection refused错误,本质是Spring Security用于获取OAuth2令牌的内部WebClient未配置公司代理,无法访问Azure Entra的令牌端点。默认情况下,Spring OAuth2客户端不会自动继承应用级代理配置,必须显式自定义令牌获取专用的WebClient。
具体解决方案
1. 配置代理参数
先在application.yml中定义代理信息(如果代理无需认证,可去掉username和password字段):
proxy: host: 你的代理主机地址 port: 你的代理端口 username: 代理认证用户名 password: 代理认证密码 spring: security: oauth2: client: registration: azure-entra: # 该ID需与后续代码中的clientRegistrationId一致 client-id: 你的Azure客户端ID client-secret: 你的Azure客户端密钥 authorization-grant-type: client_credentials # 根据实际授权类型调整,比如authorization_code scope: api://你的API范围/.default provider: azure-entra: issuer-uri: https://login.microsoftonline.com/你的租户ID/v2.0
2. 定义代理配置类
创建配置类绑定上述代理参数:
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @Component @ConfigurationProperties(prefix = "proxy") public class ProxyProperties { private String host; private int port; private String username; private String password; // Getter和Setter方法 public String getHost() { return host; } public void setHost(String host) { this.host = host; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
3. 自定义令牌获取用的WebClient及授权管理器
修改你的SecurityConfig,注入代理配置并构建带代理的WebClient:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.reactive.ReactorClientHttpConnector; import org.springframework.security.oauth2.client.AuthorizedClientServiceOAuth2AuthorizedClientManager; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction; import org.springframework.web.reactive.function.client.WebClient; import reactor.netty.http.client.HttpClient; import reactor.netty.transport.ProxyProvider; @Configuration public class SecurityConfig { private final ProxyProperties proxyProperties; public SecurityConfig(ProxyProperties proxyProperties) { this.proxyProperties = proxyProperties; } // 构建带代理的HttpClient private HttpClient createProxyHttpClient() { ProxyProvider.Builder proxyBuilder = ProxyProvider.builder() .type(ProxyProvider.Proxy.HTTP) .host(proxyProperties.getHost()) .port(proxyProperties.getPort()); // 如果代理需要认证,添加用户名密码 if (proxyProperties.getUsername() != null && !proxyProperties.getUsername().isEmpty()) { proxyBuilder.username(proxyProperties.getUsername()) .password(s -> proxyProperties.getPassword()); } return HttpClient.create().tcpConfiguration(tcpClient -> tcpClient.proxy(proxyBuilder)); } // 自定义用于获取令牌的WebClient @Bean public WebClient oauth2TokenWebClient() { return WebClient.builder() .clientConnector(new ReactorClientHttpConnector(createProxyHttpClient())) .build(); } // 配置OAuth2授权管理器,指定用自定义WebClient获取令牌 @Bean public OAuth2AuthorizedClientManager authorizedClientManager( ClientRegistrationRepository clientRegistrationRepository, OAuth2AuthorizedClientService authorizedClientService) { OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder() .clientCredentials() // 匹配你的授权类型,比如authorization_code .build(); AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager = new AuthorizedClientServiceOAuth2AuthorizedClientManager( clientRegistrationRepository, authorizedClientService); authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider); // 注入自定义WebClient到令牌获取上下文 authorizedClientManager.setContextAttributesMapper(contextAttributes -> { contextAttributes.put(ServletOAuth2AuthorizedClientExchangeFilterFunction.DEFAULT_WEB_CLIENT_ATTRIBUTE_NAME, oauth2TokenWebClient()); return contextAttributes; }); return authorizedClientManager; } // 业务调用API用的WebClient,同样配置代理并集成OAuth2认证 @Bean public WebClient apiWebClient(OAuth2AuthorizedClientManager authorizedClientManager) { ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Filter = new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager); oauth2Filter.setDefaultClientRegistrationId("azure-entra"); // 对应配置文件中的client registration ID return WebClient.builder() .clientConnector(new ReactorClientHttpConnector(createProxyHttpClient())) .filter(oauth2Filter) .build(); } }
关键注意事项
- 确保代码中的
clientRegistrationId与application.yml里的spring.security.oauth2.client.registration下的ID完全一致。 - 根据实际使用的OAuth2授权类型(如
authorization_code、password等),调整OAuth2AuthorizedClientProviderBuilder的配置项。 - 如果代理无需认证,直接删除代码中用户名密码相关的逻辑即可。
内容的提问来源于stack exchange,提问作者Wilberforce
相关产品推荐
相关产品推荐

