【问题标题】:WebClient proxy configuration not working with oAuth2WebClient 代理配置不适用于 oAuth2
【发布时间】:2020-03-27 13:14:18
【问题描述】:

我已经使用授权类型客户端凭据实现了 webclient 和 oAuth2。我必须使用代理访问局。但是webclient没有使用我配置的主机。

HttpClient httpClient = HttpClient.create()
.tcpConfiguration(tcpClient -> tcpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectionTimeout)
.doOnConnected(conn -> conn.addHandlerLast(new ReadTimeoutHandler(readTimeout, TimeUnit.MILLISECONDS)))
.proxy(proxy -> proxy.type(ProxyProvider.Proxy.HTTP).host(proxyHost).port(proxyPort)));

如果我用系统配置代理,它工作正常:

System.setProperty("proxyHost", "host);
System.setProperty("proxyPort", "8080");

但我不能在云端使用系统属性。请建议我一些解决方法或任何解决方案。

我遇到了以下异常: “org.springframework.security.oauth2.core.OAuth2AuthorizationException:[invalid_token_response] 尝试检索 OAuth 2.0 访问令牌响应时发生错误:\“https://tokenURL”的 POST 请求出现 I/O 错误:api.uat.equifax .com;嵌套异常是 java.net.UnknownHostException: resourseURL\r\n\tat org.springframework.security.oauth2.client.endpoint.DefaultClientCredentialsTokenResponseClient.getTokenResponse(DefaultClientCredentialsTokenResponseClient.java:79)\r \n\tat ...”

【问题讨论】:

  • 错误信息很清楚,未知主机“tokenURL”在我看来不是有效的主机名"host 看起来无效
  • 感谢您的回复 Adolf,实际上在我的代码中我使用的是实际主机名,但由于某些安全原因,我没有将其粘贴到此处。 proxy.type(ProxyProvider.Proxy.HTTP).host(proxyHost).port(proxyPort))
  • 正如我之前所说,错误消息很清楚,UnknownHostException
  • 是的,你是对的 Adolf,但是当我使用上面提到的 System.setProperty 设置代理时,我没有得到这个 unknownHostException。我不想使用 System 设置代理,我想通过单独使用 HttpClient 设置代理来遵循传统方法。当我们这样做时,我得到 UnknownhostException。如果可能的话,建议我一些解决方法或任何修复方法。
  • 我的建议是调试应用程序/源代码并检查抛出异常时实际存在的值。由于错误不在您发布的代码中。

标签: java spring-boot oauth-2.0 spring-webflux spring-webclient


【解决方案1】:

老问题,但它仍然是我们找到的第一个 stackoverflow 条目,所以我们决定document our solution

我们偶然发现了同样的问题。 OAuth2AuthorizationException异常表示在授权请求过程中出现问题。在对 spring-security-oauth2-client 源进行了一些挖掘之后,我们发现授权请求使用的客户端与资源请求不同。您只需为资源客户端设置代理。

授权请求正在使用 RestTemplate。以下代码 sn-p 显示了我们如何创建一个使用代理的自定义 RestTemplate 并将其添加到我们的 OAuth2AuthorizedClientManager 中。

@Bean 
public OAuth2AuthorizedClientManager authorizedClientManager( 
    final ClientRegistrationRepository clientRegistrationRepository, 
    final OAuth2AuthorizedClientService authorizedClientService) { 
 
    // Create RestTemplate that will be used for the authorization request
    // It's mandatory to add FormHttpMessageConverter and OAuth2AccessTokenResponseHttpMessageConverter
    // See javadoc from DefaultClientCredentialsTokenResponseClient.setRestOperations(RestOperations restOperations)
    // for further information
    RestTemplate restTemplate = new RestTemplate( 
        Arrays.asList(new FormHttpMessageConverter(), new OAuth2AccessTokenResponseHttpMessageConverter())); 
    restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler()); 
 
 
    // set up proxy for RestTemplate
    final HttpClientBuilder clientBuilder = HttpClientBuilder.create(); 
    clientBuilder.useSystemProperties(); 
    clientBuilder.setProxy(new HttpHost(proxyConfigDO.getHost(), proxyConfigDO.getPort())); 
 
    final CredentialsProvider credsProvider = new BasicCredentialsProvider(); 
    credsProvider.setCredentials( 
        new AuthScope(proxyConfigDO.getHost(), proxyConfigDO.getPort()), 
        new UsernamePasswordCredentials(proxyConfigDO.getUser(), proxyConfigDO.getPassword())); 
    clientBuilder.setDefaultCredentialsProvider(credsProvider); 
    clientBuilder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy()); 
 
    final CloseableHttpClient client = clientBuilder.build(); 
    final HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); 
    factory.setHttpClient(client); 
 
    restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(factory)); 
 
    // Create new client and pass our custom resttemplate 
    final var tokenResponseClient = new DefaultClientCredentialsTokenResponseClient(); 
    tokenResponseClient.setRestOperations(restTemplate); 
 
    // Create ClientCredentialsOAuth2AuthorizedClientProvider and override default setAccessTokenResponseClient
    // with the one we created in this method
    final var authorizedClientProvider = new ClientCredentialsOAuth2AuthorizedClientProvider(); 
    authorizedClientProvider.setAccessTokenResponseClient(tokenResponseClient); 
 
    final var authorizedClientManager = 
        new AuthorizedClientServiceOAuth2AuthorizedClientManager( 
            clientRegistrationRepository, authorizedClientService); 
    authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider); 
 
    return authorizedClientManager; 
}

【讨论】:

  • 嗨,麦克斯,感谢分享。当我尝试您的解决方案时,我收到消息:a bean of type 'org.springframework.security.oauth2.client.registration.ClientRegistrationRepository' that could not be found. 我感觉非常接近解决方案,但我不明白为什么这个 bean 不是由 spring 根据我的配置(使用spring.security.oauth2.client.registration 设置)创建的。有什么想法吗?
  • 嗨 Purfakt,我猜你缺少一个 spring 依赖项。我们不会手动创建 ClientRegistrationRepository bean。
猜你喜欢
  • 2020-02-29
  • 2017-07-09
  • 1970-01-01
  • 2015-10-27
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多