我正在通过需要 SSL 证书的 RestTemplate 调用外部 API。外部 API 提供商已经为我提供了证书文件 (company.crt) 及其密钥文件 (company.key)。在 Postman 中添加证书、密钥和密码时,我能够成功调用 API。但是当我在 SpringBoot 项目中使用 RestTemplate 调用时,即使在添加 SSLContext 之后,我也会收到错误消息。
我遵循的步骤:
使用 openssl 从 company.crt 和 company.key 文件创建了 company.p12 存储文件:
openssl pkcs12 -export -name servercert -in company.crt -inkey company.key -out company.p12
使用 Keytool 将 company.p12 转换为 company.jks 存储文件:
keytool -importkeystore -destkeystore company.jks -srckeystore company.p12 -srcstoretype pkcs12 -alias companycert
在将 company.jks 放在 SpringBoot 项目的资源文件夹中之后,在 application.properties 文件中创建了配置:
http.client.ssl.trust-store=classpath:company.jks
http.client.ssl.trust-store-password=Password
然后,我为 RestTemplate 创建了一个配置:
@Value("${http.client.ssl.trust-store}")
private Resource keyStore;
@Value("${http.client.ssl.trust-store-password}")
private String keyStorePassword;
@Bean
RestTemplate restTemplate() throws Exception {
SSLContext sslContext = new SSLContextBuilder()
.loadTrustMaterial(
keyStore.getURL(),
keyStorePassword.toCharArray()
).build();
SSLConnectionSocketFactory socketFactory =
new SSLConnectionSocketFactory(sslContext);
HttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(socketFactory).build();
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory(httpClient);
return new RestTemplate(factory);
}
调用外部 API:
@Autowired
RestTemplate restTemplate;
@GetMapping("/api")
public Object callAPI() {
final String ENDPOINT = "https://some-api.domain.com:8533/api/key/";
Object response = restTemplate.exchange(ENDPOINT, HttpMethod.GET, request, Object.class);
return response;
}
通过 RestTemplate 调用 API 后的错误:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target