Spring 5 WebClient 使用 ssl
Spring 5 WebClient using ssl
我正在寻找使用 WebClient 的示例。
我的目标是使用 Spring 5 WebClient 查询使用 https 和自签名证书的 REST 服务
有例子吗?
查看信任所有 X.509 证书(包括自签名)而无需任何验证的使用示例 insecure TrustManagerFactory。文档中的重要说明:
Never use this TrustManagerFactory in production. It is purely for testing purposes, and thus it is very insecure.
@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();
}
必须对此进行编辑,以适应 spring-boot 2.0->2.1 的更改。
另一种方法,如果你想编写生产代码,创建一个这样的 spring bean,修改注入的 WebClient,使用 spring-boot 服务器的设置信任库和密钥库是。在客户端中,如果您使用的是 2-way-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);
}
};
}
这是您使用 Web 客户端的部分:
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();
}
}
看起来 Spring 5.1.1 (Spring boot 2.1.0) 从 ReactorClientHttpConnector
中删除了 HttpClientOptions
,因此您无法在创建 [的实例时配置选项=14=]
现在有效的一个选项是:
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()
更多信息:
- https://docs.spring.io/spring/docs/5.1.1.RELEASE/spring-framework-reference/web-reactive.html#webflux-client-builder-reactor
- https://netty.io/4.0/api/io/netty/handler/ssl/util/InsecureTrustManagerFactory.html
更新:Java 相同代码的版本
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();
对于那些可能坚持如何使用反应式 WebFlux webClient
来使用受 https 保护的 REST API 的人
您想创建两个东西
- https 已启用 REST API - https://github.com/mghutke/HttpsEnabled
- 另一个 REST API 作为 WebClient 的客户端使用以上一个 - https://github.com/mghutke/HttpsClient
注意:请通过上面的项目查看与上述 spring 启动应用程序共享的密钥库。并以编程方式添加了 keyManagerFactory 和 TrustManagerFactory。
我正在寻找使用 WebClient 的示例。
我的目标是使用 Spring 5 WebClient 查询使用 https 和自签名证书的 REST 服务
有例子吗?
查看信任所有 X.509 证书(包括自签名)而无需任何验证的使用示例 insecure TrustManagerFactory。文档中的重要说明:
Never use this TrustManagerFactory in production. It is purely for testing purposes, and thus it is very insecure.
@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();
}
必须对此进行编辑,以适应 spring-boot 2.0->2.1 的更改。
另一种方法,如果你想编写生产代码,创建一个这样的 spring bean,修改注入的 WebClient,使用 spring-boot 服务器的设置信任库和密钥库是。在客户端中,如果您使用的是 2-way-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);
}
};
}
这是您使用 Web 客户端的部分:
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();
}
}
看起来 Spring 5.1.1 (Spring boot 2.1.0) 从 ReactorClientHttpConnector
中删除了 HttpClientOptions
,因此您无法在创建 [的实例时配置选项=14=]
现在有效的一个选项是:
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()
更多信息:
- https://docs.spring.io/spring/docs/5.1.1.RELEASE/spring-framework-reference/web-reactive.html#webflux-client-builder-reactor
- https://netty.io/4.0/api/io/netty/handler/ssl/util/InsecureTrustManagerFactory.html
更新:Java 相同代码的版本
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();
对于那些可能坚持如何使用反应式 WebFlux webClient
来使用受 https 保护的 REST API 的人您想创建两个东西
- https 已启用 REST API - https://github.com/mghutke/HttpsEnabled
- 另一个 REST API 作为 WebClient 的客户端使用以上一个 - https://github.com/mghutke/HttpsClient
注意:请通过上面的项目查看与上述 spring 启动应用程序共享的密钥库。并以编程方式添加了 keyManagerFactory 和 TrustManagerFactory。