Spring Security 6.5:让 OAuth 授权码交换走代理
为 Spring Security 的授权码令牌响应客户端提供支持代理的 RestClient,同时保留其 OAuth 转换器和错误处理器。
浏览器能访问身份提供方,但应用交换返回的授权码时登录却失败了。这次交换是应用服务器发出的出站请求,有它自己的 HTTP 客户端。
对于 Spring Security 6.5 中基于 RestClient 的 API,为授权码令牌响应客户端提供支持代理的请求工厂:
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setProxy(new java.net.Proxy(
java.net.Proxy.Type.HTTP,
new java.net.InetSocketAddress("proxy.example", 8080)));
factory.setConnectTimeout(5000);
factory.setReadTimeout(15000);
RestClient tokenHttp = RestClient.builder()
.requestFactory(factory)
.messageConverters(converters -> {
converters.clear();
converters.add(new FormHttpMessageConverter());
converters.add(new OAuth2AccessTokenResponseHttpMessageConverter());
})
.defaultStatusHandler(new OAuth2ErrorResponseErrorHandler())
.build();
RestClientAuthorizationCodeTokenResponseClient tokenClient =
new RestClientAuthorizationCodeTokenResponseClient();
tokenClient.setRestClient(tokenHttp);
转换器和错误处理器类保留了 Spring Security 文档中描述的令牌请求行为。仅为无关 JSON API 配置的通用 RestClient 并不是等效替代。
把同一个 tokenClient 接入现有安全配置:
http.oauth2Login(login -> login
.tokenEndpoint(token -> token
.accessTokenResponseClient(tokenClient)));
这些是配置片段,适用于已经具备客户端注册和 SecurityFilterChain 的应用。它们选择不带身份验证的 HTTP 代理;需要凭据的代理则要使用所选传输方式对应的身份验证配置。对于允许的公共路由上可公开访问的 HTTPS 令牌端点,来自 HTTP 代理列表的 HTTP 条目可以填入那个无需账号的代理地址。
把代理主机与它的端口和 URL 方案分开。让身份提供方的令牌 URI 保持为目标地址。示例并不替代证书校验。
后续请求需要各自的归属检查。UserInfo 获取、刷新令牌交换、client_credentials 授权以及受保护 API 调用可以使用其他客户端对象。当该操作也需要这条路由时,配置相应的受支持客户端。对于 Spring Security 6.5 的响应式 client_credentials 流程,请另行配置响应式令牌客户端及其授权提供者。
使用 OAuth2RestTemplate 和 AccessTokenProvider 的旧示例属于更早的 Spring Security OAuth 项目。在改造代码之前,先选择已安装应用所用的 API;不要把这些对象混入本配置。