如何在Spring Boot Rest模板中使用.pfx证书和密码调用安全的REST API?

问题描述

我需要从我的spring boot应用程序中调用一个外部安全的REST API(已启用ssl)。邮递员可使用.pfx证书和密码访问外部api。 现在,我想使用rest模板通过在每个请求上附加.pfx文件密码调用外部api。

我不知道如何使用pfx证书通过ssl进行剩余模板调用。任何帮助将不胜感激。

解决方法

您需要做的是配置其余模板的基础apache http客户端。下面是一个示例配置:

SSLContext sslContext = ...;

HttpClient httpClient = HttpClients.custom()
    .setSSLContext(sslContext)
    .build();

HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);

RestTemplate restTemplate = new RestTemplate(requestFactory);

有两个库提供了易于使用的实用程序/工厂/生成器类,以帮助您创建SSLContext。

可能还有许多其他提供类似功能的库,但是我只知道这三个。顺便说一下,sslcontext-kickstart是一个由我维护的库。

下面是加载密钥库和创建​​SSLContext的四种方法的概述。 Vanilla Java并使用这三个库。

import io.netty.handler.ssl.SslContextBuilder;
import nl.altindag.sslcontext.SSLFactory;
import org.apache.http.ssl.SSLContextBuilder;
import org.eclipse.jetty.util.ssl.SslContextFactory;

import javax.net.ssl.*;
import java.io.File;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.Objects;

class SslExample {

    public static void main(String[] args) throws Exception {

        //Traditional flow of creating sslContext
        String keyStorePath = "keystore.pfx";
        String trustStorePath = "truststore.pfx";

        char[] keyStorePassword = "secret".toCharArray();
        char[] trustStorePassword = "secret".toCharArray();

        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        KeyStore trustStore = KeyStore.getInstance("PKCS12");

        try(InputStream keyStoreInputStream = SslExample.class.getClassLoader().getResourceAsStream(keyStorePath);
            InputStream trustStoreInputStream = SslExample.class.getClassLoader().getResourceAsStream(trustStorePath)) {

            Objects.requireNonNull(keyStoreInputStream);
            Objects.requireNonNull(trustStoreInputStream);

            keyStore.load(keyStoreInputStream,keyStorePassword);
            trustStore.load(trustStoreInputStream,trustStorePassword);
        }

        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyManagerFactory.init(keyStore,keyStorePassword);
        KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();

        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(trustStore);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();

        SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
        sslContext.init(keyManagers,trustManagers,new SecureRandom());

        //creating sslContext with Apache SSLContextBuilder
        SSLContext sslContext1 = SSLContextBuilder.create()
                .loadKeyMaterial(new File("keystore.pfx"),"secret".toCharArray(),"secret".toCharArray())
                .loadTrustMaterial(new File("truststore.pfx"),"secret".toCharArray())
                .build();

        //creating sslContext with Jetty SslContextFactory
        SslContextFactory.Client sslContextFactory = new SslContextFactory.Client();
        sslContextFactory.setKeyStorePath("keystore.pfx");
        sslContextFactory.setKeyStorePassword("secret");
        sslContextFactory.setTrustStorePath("truststore.pfx");
        sslContextFactory.setTrustStorePassword("secret");
        sslContextFactory.start();

        SSLContext sslContext2 = sslContextFactory.getSslContext();

        //creating sslContext with sslcontext-kickstart
        SSLFactory sslFactory = SSLFactory.builder()
                .withIdentityMaterial("keystore.pfx","secret".toCharArray())
                .withTrustMaterial("truststore.pfx","secret".toCharArray())
                .build();

        SSLContext sslContext3 = sslFactory.getSslContext();
    }

}