使用SSL的Spring 5 Web客户端

332nm8kg  于 2022-10-30  发布在  Spring
关注(0)|答案(5)|浏览(158)

我试图找到使用WebClient的示例。
我的目标是使用Spring5WebClient来查询使用https和自签名证书的REST服务
举个例子吧?

2w2cym1i

2w2cym1i1#

看起来Spring 5.1.1(Sping Boot 2.1.0)从ReactorClientHttpConnector中删除了HttpClientOptions,因此在创建ReactorClientHttpConnector的示例时无法配置选项
现在有效的一个选项是:

val sslContext = SslContextBuilder
            .forClient()
            .trustManager(InsecureTrustManagerFactory.INSTANCE)
            .build()
val httpClient = HttpClient.create().secure { t -> t.sslContext(sslContext) }
val webClient = WebClient.builder().clientConnector(ReactorClientHttpConnector(httpClient)).build()

基本上,在创建HttpClient时,我们将配置不安全sslContext,然后全局传递此httpClient以在ReactorClientHttpConnector中使用。

另一个选项是使用不安全的sslContext配置TcpClient,并使用它创建HttpClient示例,如下所示:

val sslContext = SslContextBuilder
            .forClient()
            .trustManager(InsecureTrustManagerFactory.INSTANCE)
            .build()
val tcpClient = TcpClient.create().secure { sslProviderBuilder -> sslProviderBuilder.sslContext(sslContext) }
val httpClient = HttpClient.from(tcpClient)
val webClient =  WebClient.builder().clientConnector(ReactorClientHttpConnector(httpClient)).build()

如欲了解更多信息,请访问:

SslContext context = SslContextBuilder.forClient()
    .trustManager(InsecureTrustManagerFactory.INSTANCE)
    .build();

HttpClient httpClient = HttpClient.create().secure(t -> t.sslContext(context));

WebClient wc = WebClient
                    .builder()
                    .clientConnector(new ReactorClientHttpConnector(httpClient)).build();
mwngjboj

mwngjboj2#

请参阅使用insecure TrustManagerFactory的示例,该示例信任所有X.509证书(包括自签名证书)而不进行任何验证。文档中的重要说明:
切勿在生产环境中使用此TrustManagerFactory。它纯粹用于测试目的,因此非常不安全。

@Bean
public WebClient createWebClient() throws SSLException {
    SslContext sslContext = SslContextBuilder
            .forClient()
            .trustManager(InsecureTrustManagerFactory.INSTANCE)
            .build();
    ClientHttpConnector httpConnector = HttpClient.create().secure(t -> t.sslContext(sslContext) )
    return WebClient.builder().clientConnector(httpConnector).build();
}
mrphzbgm

mrphzbgm3#

必须编辑此内容,以适应spring-boot 2.0-〉2.1的更改。

另一种方法,如果你想编写生产代码,创建一个类似这样的spring bean,它使用spring-boot服务器中信任库和密钥库所在的设置来修改注入的WebClient。在客户端,如果你使用的是双向ssl,你只需要给予密钥库。不知道为什么ssl-stuff没有预先配置,并且很容易注入,类似于真正酷的spring-boot服务器设置。

import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
.
.
.

  @Bean
  WebClientCustomizer configureWebclient(@Value("${server.ssl.trust-store}") String trustStorePath, @Value("${server.ssl.trust-store-password}") String trustStorePass,
      @Value("${server.ssl.key-store}") String keyStorePath, @Value("${server.ssl.key-store-password}") String keyStorePass, @Value("${server.ssl.key-alias}") String keyAlias) {

      return (WebClient.Builder webClientBuilder) -> {
          SslContext sslContext;
          final PrivateKey privateKey;
          final X509Certificate[] certificates;
          try {
            final KeyStore trustStore;
            final KeyStore keyStore;
            trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(new FileInputStream(ResourceUtils.getFile(trustStorePath)), trustStorePass.toCharArray());
            keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(new FileInputStream(ResourceUtils.getFile(keyStorePath)), keyStorePass.toCharArray());
            List<Certificate> certificateList = Collections.list(trustStore.aliases())
                .stream()
                .filter(t -> {
                  try {
                    return trustStore.isCertificateEntry(t);
                  } catch (KeyStoreException e1) {
                    throw new RuntimeException("Error reading truststore", e1);
                  }
                })
                .map(t -> {
                  try {
                    return trustStore.getCertificate(t);
                  } catch (KeyStoreException e2) {
                    throw new RuntimeException("Error reading truststore", e2);
                  }
                })
                .collect(Collectors.toList());
            certificates = certificateList.toArray(new X509Certificate[certificateList.size()]);
            privateKey = (PrivateKey) keyStore.getKey(keyAlias, keyStorePass.toCharArray());
            Certificate[] certChain = keyStore.getCertificateChain(keyAlias);
            X509Certificate[] x509CertificateChain = Arrays.stream(certChain)
                .map(certificate -> (X509Certificate) certificate)
                .collect(Collectors.toList())
                .toArray(new X509Certificate[certChain.length]);
            sslContext = SslContextBuilder.forClient()
                .keyManager(privateKey, keyStorePass, x509CertificateChain)
                .trustManager(certificates)
                .build();

            HttpClient httpClient = HttpClient.create()
                .secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
            ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);
            webClientBuilder.clientConnector(connector);
          } catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException | UnrecoverableKeyException e) {
            throw new RuntimeException(e);
          }
        };
  }

下面是使用Webclient的部分:

import org.springframework.web.reactive.function.client.WebClient;

@Component
public class ClientComponent {

  public ClientComponent(WebClient.Builder webClientBuilder, @Value("${url}") String url) {
    this.client = webClientBuilder.baseUrl(solrUrl).build();
  }
}
0s7z1bwu

0s7z1bwu4#

对于那些可能在如何使用受https保护的REST API和响应式WebFluxwebClient方面遇到困难的用户
你要创造两样东西
1.支持https的REST API -https://github.com/mghutke/HttpsEnabled
1.另一个REST API作为客户端与WebClient一起使用-https://github.com/mghutke/HttpsClient
注意:请浏览上述项目,查看与上述两个Spring Boot 应用程序共享的密钥库。并以编程方式添加了keyManagerFactory和TrustManagerFactory。

m4pnthwp

m4pnthwp5#

Spring框架版本5.3.23(Sping Boot 版本2.7.4)您可以尝试使用ReactorClientHttpConnector的这种方式:

SslContext context = SslContextBuilder.forClient()
    .trustManager(InsecureTrustManagerFactory.INSTANCE)
    .build();

HttpClient httpClient = HttpClient.create().secure(t -> t.sslContext(context));

WebClient wc = WebClient
                    .builder()
                    .clientConnector(new ReactorClientHttpConnector(httpClient)).build();

我希望这个答案对你有帮助。

相关问题