gpt4 book ai didi

java - 如何配置 Reactive WebClient 以使用 2-way TLS?

转载 作者:太空宇宙 更新时间:2023-11-03 13:20:47 27 4
gpt4 key购买 nike

我正在尝试配置响应式(Reactive) WebClient 以使用双向 TLS。我用了this answer作为引用。 (使用 WebClientCustomizer 的那个,而不是使用 InsecureTrustManager 的那个)。

我仔细检查了客户端和服务器端的 keystore 和信任库,但服务器发回错误消息说客户端没有提供任何证书:

  @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 new WebClientCustomizer() {

@Override
public void customize(Builder webClientBuilder) {
SslContext sslContext;
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(new FileInputStream(ResourceUtils.getFile(trustStorePath)), trustStorePass.toCharArray());

List<Certificate> certificateCollcetion = 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());

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(new FileInputStream(ResourceUtils.getFile(keyStorePath)), keyStorePass.toCharArray());
sslContext = SslContextBuilder.forClient()
.keyManager((PrivateKey) keyStore.getKey(keyAlias, keyStorePass.toCharArray()))
.trustManager((X509Certificate[]) certificateCollcetion.toArray(new X509Certificate[certificateCollcetion.size()]))
.build();
} catch (Exception e) {
log.error("Error creating web client", e);
throw new RuntimeException(e);
}
ClientHttpConnector connector = new ReactorClientHttpConnector((opt) -> {
opt.sslContext(sslContext);
});
webClientBuilder.clientConnector(connector);
}
};
}

有人可以分享有关如何正确配置响应式(Reactive) WebClient 以使用双向 TLS 的见解吗?

最佳答案

出于某种原因,当 ssl 上下文构建如下时,服务器不会接受客户端证书:

sslContext = SslContextBuilder.forClient()
.keyManager((PrivateKey) keyStore.getKey(keyAlias, keyStorePass.toCharArray()))
.trustManager((X509Certificate[]) certificateCollcetion.toArray(new X509Certificate[certificateCollcetion.size()]))
.build();

为了解决这个问题,我必须初始化一个 KeyManagerFactory:

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keyStore, keyStorePass.toCharArray());

然后我用工厂初始化了 ssl 上下文:

SslContext sslContext = SslContextBuilder.forClient()
.keyManager(keyManagerFactory)
.trustManager((X509Certificate[]) certificateCollection.toArray(new X509Certificate[certificateCollection.size()]))
.build();

之后,服务器接受了证书,我就可以连接了。

总而言之,我使用了将工厂用于 keystore 和信任库的更简洁的解决方案:

@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;

@Bean
public WebClient create2WayTLSWebClient() {

ClientHttpConnector connector = new ReactorClientHttpConnector(
options -> {
options.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000);
options.sslContext(get2WaySSLContext());
}
);

return WebClient.builder()
.clientConnector(connector)
.build();

}

private SslContext get2WaySSLContext() {

try {

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(new FileInputStream(ResourceUtils.getFile(keyStorePath)), keyStorePass.toCharArray());

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keyStore, keyStorePass.toCharArray());

KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(new FileInputStream(ResourceUtils.getFile(trustStorePath)), trustStorePass.toCharArray());

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
trustManagerFactory.init(trustStore);

return SslContextBuilder.forClient()
.keyManager(keyManagerFactory)
.trustManager(trustManagerFactory)
.build();

} catch (Exception e) {
logger.error("Error creating 2-Way TLS WebClient. Check key-store and trust-store.");
e.printStackTrace();
}

return null;
}

请注意,如果您使用的是 Spring 5.1 或更新版本,则此特定实现将不起作用,因为您无法再将 HttpClientOptions 传递给 ReactorClientHttpConnector。使用 this link作为该配置的指南。但是,此答案中的代码内容仍应适用于那种配置。

关于java - 如何配置 Reactive WebClient 以使用 2-way TLS?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53341607/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com