浏览器能访问身份提供方,但应用交换返回的授权码时登录却失败了。这次交换是应用服务器发出的出站请求,有它自己的 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;不要把这些对象混入本配置。

相关文章