在 Spring Boot 2.0 中使用 Web Client 访问 HTTPS RESTful 服务抛出异常 [英] Access HTTPS RESTful service using Web Client in Spring Boot 2.0 throwing exception
问题描述
我必须访问一个 https 休息网络服务 (https://example.com)由客户端提供,其中包含 2 个 .cer 文件.
I have to access one https rest web service(https://example.com) for which certificate has been provided by the client which contains 2 .cer files.
我已经创建了keystore.jks
和truststore.jks
文件,并且将.cer 文件导入到jks 文件
.使用下面的命令
I have created keystore.jks
and truststore.jks
files and imported the .cer files to jks file
. by using the below command
keytool -genkeypair -alias abcd -keyalg RSA -sigalg garegar -keysize 2048 -storetype jks -keystore keystore.jks -validity 365 -storepass changeit
keytool -import -alias abcd -trustcacerts -file free/ca_bundle.cer -keystore keystore.jksccessfull
我已将所有属性添加到 application.yml
I have added all properties to application.yml
truststore-location:
keystore-location:
truststore-password:
keystore-password:
key-alias:
在配置类中创建 bean 以获取 webclient 对象.
Created the bean in configuration class to get the webclient object.
@Data
@NoArgsConstructor
@AllArgsConstructor
@Configuration
public class WebServiceRestConfig {
@Value(value = "${wcc.rest.endpoint}")
private String url;
@Value(value = "${wcc.dam.username}")
private String username;
@Value(value = "${wcc.dam.password}")
private String password;
@Value(value = "${ssl.truststore-location}")
private String trustStore;
@Value(value = "${ssl.keystore-location}")
private String keyStore;
@Value(value = "${ssl.truststore-password}")
private String trustStorePassword;
@Value(value = "${ssl.keystore-password}")
private String keyStorePassword;
@Value(value = "${ssl.key-alias}")
private String keyAlias;
@Bean
WebClientCustomizer configureWebclient() {
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(getTrustStore())),
trustStorePassword.toCharArray());
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(new FileInputStream(ResourceUtils.getFile(getKeyStore())), keyStorePassword.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, keyStorePassword.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, keyStorePassword, x509CertificateChain)
.trustManager(certificates).build();
HttpClient httpClient = HttpClient.create()
.secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);
webClientBuilder.clientConnector(connector).baseUrl(getUrl()).build();
} catch (KeyStoreException e) {
throw new RuntimeException(e);
}catch(CertificateException e) {
throw new RuntimeException(e);
}catch(NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}catch(IOException e) {
throw new RuntimeException(e);
}catch(UnrecoverableKeyException e) {
throw new RuntimeException(e);
}
};
}
}
但是当我运行应用程序时,我遇到了异常
But when i am running the application I am getting below exception
SEVERE: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is reactor.core.Exceptions$ReactiveException: javax.net.ssl.SSLHandshakeException: General SSLEngine problem] with root cause
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:145)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:131)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:281)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:136)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1465)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:212)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:969)
现在我完全不知道该怎么做以及如何解决这个问题我需要在资源文件夹中添加任何东西还是我在这里遗漏了什么?
Right now I am completely clueless what to do and how to resolve this do i need to add anything in resources folder or am i missing something here?
推荐答案
我遇到了类似的问题:
@Bean("oAuth2")
public WebClient webOAuth2Client(ReactiveClientRegistrationRepository registration,
ServerOAuth2AuthorizedClientRepository clientRepository) {
ServerOAuth2AuthorizedClientExchangeFilterFunction filter =
new ServerOAuth2AuthorizedClientExchangeFilterFunction(
registration,
clientRepository);
filter.setDefaultClientRegistrationId("oAuth2");
return WebClient
.builder()
.filter(filter)
.build();
}
在属性文件中类似:
security:
oauth2:
client:
provider:
oAuth2:
token-uri: url:port/auth/realms/SCRealm/protocol/openid-connect/token
registration:
oAuth2:
clientId: client_id
clientSecret: client_secret
authorizationGrantType: client_credentials
clientAuthenticationMethod: post
在主应用程序类中:
System.setProperty("-Dio.netty.handler.ssl.noOpenSsl","true");
System.setProperty("javax.net.ssl.trustStore", "keyStore.jks");
System.setProperty("javax.net.ssl.trustStoreType", "JKS");
System.setProperty("javax.net.ssl.trustStorePassword", "any_strong_pass");
这篇关于在 Spring Boot 2.0 中使用 Web Client 访问 HTTPS RESTful 服务抛出异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!