给 RestTemplate 配置 SSL 证书来访问 HTTPS REST 服务

1、概览

在本教程中,我们将学习如何给 RestTemplate 配置 SSL 证书来访问 HTTPS 加密的 REST 服务。

2、设置

要确保 REST 服务的安全,我们需要使用证书和由证书生成的 Keystore。

证书可以从 CA 获取,在本文的示例中,使用的是自签名证书。

我们将使用 Spring 的 RestTemplate 来访问 HTTPS REST 服务。

首先,让我们创建一个 Controller 类 WelcomeController 和一个 /welcome 端点(返回一个简单的字符串响应):

@RestController
public class WelcomeController {

    @GetMapping(value = "/welcome")
    public String welcome() {
       return "Welcome To Secured REST Service";
    }
}

然后,在 src/main/resources 文件夹中添加我们的 keystore:

src/main/resources
|-keystore
  |-baeldung.p12

接下来,在 application.properties 文件中添加与 Keystore 相关的属性:

server.port=8443
server.servlet.context-path=/
# keystore 的格式
server.ssl.key-store-type=PKCS12
# 包含证书的 keystore 的路径
server.ssl.key-store=classpath:keystore/baeldung.p12
# 生成证书时使用的密码
server.ssl.key-store-password=password
# 证书的别名
server.ssl.key-alias=baeldung

现在我们可以通过以下端点访问 REST 服务:https://localhost:8443/welcome

3、访问 Secured REST 服务

Spring 提供了一个方便的 RestTemplate 类来访问 REST 服务。

访问简单的 REST 服务很简单,但在访问 Secured REST 服务时,我们需要根据服务使用的证书/Keystore 来自定义 RestTemplate

接下来,创建一个简单的 RestTemplate 对象,添加所需的证书/Keystore。

3.1、创建 RestTemplate

编写一个简单的 Controller,使用 RestTemplate 来调用 REST 服务:

@RestController
public class RestTemplateClientController {
    private static final String WELCOME_URL = "https://localhost:8443/welcome";

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/welcomeclient")
    public String greetMessage() {
        String response = restTemplate.getForObject(WELCOME_URL, String.class);
        return response;
    }
}

如果运行代码并访问 /welcomeclient 端点,就会出现异常,因为找不到访问 Secured REST 服务的有效证书:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: 
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested 
target at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)

接下来,我们看看如何解决这个错误。

3.2、配置 RestTemplate 以访问 HTTPS

访问 Secured REST 服务的客户端应用应在其 resources 文件夹中包含一个 Secure Keystore。此外,还需要对 RestTemplate 进行配置。

首先,在 /src/main/resources 文件夹中添加之前的 Keystore baeldung.p12 作为 truststore:

src/main/resources
|-keystore
  |-baeldung.p12

接下来,需要在 application.properties 文件中添加 truststore 详情:

server.port=8082
# trust store 位置
trust.store=classpath:keystore/baeldung.p12
# trust store 密码
trust.store.password=password

最后,自定义 RestTemplate,添加 truststore

@Configuration
public class CustomRestTemplateConfiguration {

    @Value("${trust.store}")
    private Resource trustStore;

    @Value("${trust.store.password}")
    private String trustStorePassword;

    @Bean
    public RestTemplate restTemplate() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException,
      CertificateException, MalformedURLException, IOException {
      
        SSLContext sslContext = new SSLContextBuilder()
          .loadTrustMaterial(trustStore.getURL(), trustStorePassword.toCharArray()).build();
        SSLConnectionSocketFactory sslConFactory = new SSLConnectionSocketFactory(sslContext);

        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslConFactory).build();
        ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
        return new RestTemplate(requestFactory);
    }
}

restTemplate() 放中。首先,我们使用 SSLContextBuilder 类的 build() 方法来创建一个表示 Secure Socket Protocol 实现的 SSLContext 对象。

我们使用 SSLContextBuilderloadTrustMaterial() 方法将 keystore 文件和凭据加载到 SSLContext 对象中。

然后,我们通过加载 SSLContext 创建 SSLConnectionSocketFactory,这是一个用于 TSL 和 SSL 连接的分层 Socket Factory。这一步的目的是验证服务器是否使用了我们在上一步中加载的受信任证书列表,即对服务器进行身份验证。

现在,我们可以使用自定义的 RestTemplate 在端点 http://localhost:8082/welcomeclient 中访问 Secured REST 服务,并返回结果:

$ curl localhost:8082/welcomeclient
Welcome To Secured REST Service

4、总结

在本文中,我们学习了如何给 RestTemplate 配置 SSL 证书来访问 Secured REST 服务。


参考:https://www.baeldung.com/spring-resttemplate-secure-https-service