如何在Spring的RestTemplate中每个请求中正确发送客户端证书?

31

我希望使用Spring应用程序调用一个REST服务。为了访问该服务,我有一个客户端证书(自签名且格式为.jks)用于授权。

如何正确地对REST服务进行身份验证?

这是我的请求:

public List<Info> getInfo() throws RestClientException, URISyntaxException {

    HttpEntity<?> httpEntity = new HttpEntity<>(null, new HttpHeaders());

    ResponseEntity<Info[]> resp = restOperations.exchange(
            new URI(BASE_URL + "/Info"), HttpMethod.GET, 
            httpEntity, Info[].class);
    return Arrays.asList(resp.getBody());
}
2个回答

50

以下是使用 RestTemplateApache HttpClient 的示例。

您应该定义自己配置了 SSL 上下文的 RestTemplate

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) throws Exception {
    char[] password = "password".toCharArray();

    SSLContext sslContext = SSLContextBuilder.create()
            .loadKeyMaterial(keyStore("classpath:cert.jks", password), password)
            .loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();

    HttpClient client = HttpClients.custom().setSSLContext(sslContext).build();
    return builder
            .requestFactory(new HttpComponentsClientHttpRequestFactory(client))
            .build();
}

 private KeyStore keyStore(String file, char[] password) throws Exception {
    KeyStore keyStore = KeyStore.getInstance("PKCS12");
    File key = ResourceUtils.getFile(file);
    try (InputStream in = new FileInputStream(key)) {
        keyStore.load(in, password);
    }
    return keyStore;
}
现在,该模板执行的所有远程调用都将使用 cert.jks 进行签名。 注意:您需要将 cert.jks 放入类路径中。
@Autowired
private RestTemplate restTemplate;

public List<Info> getInfo() throws RestClientException, URISyntaxException {
    HttpEntity<?> httpEntity = new HttpEntity<>(null, new HttpHeaders());

    ResponseEntity<Info[]> resp = restTemplate.exchange(
            new URI(BASE_URL + "/Info"), HttpMethod.GET, 
            httpEntity, Info[].class);
    return Arrays.asList(resp.getBody());
}

8
请注意,您可以直接在 RestTemplate 对象上调用 setRequestFactory 方法,而无需使用 RestTemplateBuilder - ChocolateAndCheese
我没有.jks文件。我从GoDaddy下载了客户端证书,有两个文件是.crt.pem。我尝试使用这些文件运行代码,但它抛出异常java.io.IOException: Invalid keystore format。请指导。谢谢。 - Ankur Raiyani
将 .pem 转换为 .jks - Glare Storm
以上代码对我不起作用。我从https://www.sslshopper.com/ssl-converter.html生成了一堆pem文件的pfx/pkcs12,并将pkcs12转换为jks。 - user1354825

-2

或者您可以将证书导入到您的JDK cacerts中,所有使用jdk的HTTP客户端(在您的情况下是rest模板)都将使用证书来进行REST调用。

keytool -import -keystore $JAVA_HOME/jre/lib/security/cacerts -file foo.cer -alias alias

提示:在成功导入后不要忘记重新启动服务器。密钥库的默认密码为changeit


9
如果我有几个不同的证书要用于不同的调用,这会造成问题吗? - Janac Meena
1
当cacerts存储中存在多个证书时,Java如何知道使用哪个客户端证书? - DAN
7
客户端证书未在cacerts文件中指定。这适用于类似于服务器证书签名证书等受信任的证书。但是,这个答案是错误的。 - Chris D

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接