0

我正在通过需要 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
4

1 回答 1

0

解决了:

application.properties配置:添加密钥存储属性

http.client.ssl.trust-store=classpath:company.jks
http.client.ssl.trust-store-password=Password

http.client.ssl.key-store=classpath:company.p12
http.client.ssl.key-store-password=Password

然后,在RestTemplate配置中:

@Bean
RestTemplate restTemplate() throws Exception {

    TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;

    SSLContext sslContext = new SSLContextBuilder()
        .loadTrustMaterial(
            trustStore.getURL(),
            trustStorePassword.toCharArray(), acceptingTrustStrategy
         )
         .loadKeyMaterial(
             keyStore.getURL(), 
             keyStorePassword.toCharArray(), 
             keyStorePassword.toCharArray())
         .build();

    SSLConnectionSocketFactory socketFactory = 
        new SSLConnectionSocketFactory(sslContext);

    HttpClient httpClient = HttpClients.custom()
        .setSSLSocketFactory(socketFactory).build();

    HttpComponentsClientHttpRequestFactory factory = 
        new HttpComponentsClientHttpRequestFactory(httpClient);

    return new RestTemplate(factory);

}
于 2020-12-08T10:52:52.253 回答