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

huangapple go评论73阅读模式
英文:

How to call secured rest api using .pfx certificate & password in spring boot rest template?

问题

我需要从我的Spring Boot应用程序调用一个外部安全的REST API(启用SSL)。可以使用.pfx证书和密码从Postman访问外部API。
现在,我想使用rest template调用外部API,在每个请求中附上.pfx文件和密码。

我不知道如何使用pfx证书使rest template在SSL上进行调用。任何帮助将不胜感激。

英文:

I need to invoke an external secured rest api(ssl enabled) from my spring boot application. The external api is accessible from postman using .pfx certificate & password.
Now I would like to make a call to the external api using rest template by attaching .pfx file and password on each request.

I don’t know how to make rest template call over ssl using pfx certificate. Any help will be appreciated.

答案1

得分: 4

你需要做的是配置RestTemplate的底层Apache Http Client。以下是一个示例配置:

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的四种方法的概述。使用纯Java和三个库。

import io.netty.handler.ssl.SslContextBuilder;
import nl.altindag.ssl.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 {

        // 使用sslcontext-kickstart创建sslContext
        SSLFactory sslFactory = SSLFactory.builder()
                .withIdentityMaterial("keystore.pfx", "secret".toCharArray())
                .withTrustMaterial("truststore.pfx", "secret".toCharArray())
                .build();

        SSLContext sslContext = sslFactory.getSslContext();

        // 创建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 sslContext1 = SSLContext.getInstance("TLSv1.2");
        sslContext.init(keyManagers, trustManagers, new SecureRandom());

        // 使用Apache SSLContextBuilder创建sslContext
        SSLContext sslContext2 = SSLContextBuilder.create()
                .loadKeyMaterial(new File("keystore.pfx"), "secret".toCharArray(), "secret".toCharArray())
                .loadTrustMaterial(new File("truststore.pfx"), "secret".toCharArray())
                .build();

        // 使用Jetty SslContextFactory创建sslContext
        SslContextFactory.Client sslContextFactory = new SslContextFactory.Client();
        sslContextFactory.setKeyStorePath("keystore.pfx");
        sslContextFactory.setKeyStorePassword("secret");
        sslContextFactory.setTrustStorePath("truststore.pfx");
        sslContextFactory.setTrustStorePassword("secret");
        sslContextFactory.start();

        SSLContext sslContext3 = sslContextFactory.getSslContext();
    }

}
英文:

What you need to do is to configure the underlying apache http client of the rest template. Below is an example configuration:

SSLContext sslContext = ...;
HttpClient httpClient = HttpClients.custom()
.setSSLContext(sslContext)
.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
RestTemplate restTemplate = new RestTemplate(requestFactory);

There are couple of libraries which provides easy to use utility/factory/builder classes to help you to create a SSLContext.

There could be a bunch other libraries which provide similar functionality, but I am only aware of these three. By the way the sslcontext-kickstart is a library which is maintained by me.

Below is an overview of four ways to load the keystores and create an SSLContext. Vanilla Java and by using the three libraries.

import io.netty.handler.ssl.SslContextBuilder;
import nl.altindag.ssl.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 {
//creating sslContext with sslcontext-kickstart
SSLFactory sslFactory = SSLFactory.builder()
.withIdentityMaterial("keystore.pfx", "secret".toCharArray())
.withTrustMaterial("truststore.pfx", "secret".toCharArray())
.build();
SSLContext sslContext = sslFactory.getSslContext();
//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 sslContext1 = SSLContext.getInstance("TLSv1.2");
sslContext.init(keyManagers, trustManagers, new SecureRandom());
//creating sslContext with Apache SSLContextBuilder
SSLContext sslContext2 = 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 sslContext3 = sslContextFactory.getSslContext();
}
}

huangapple
  • 本文由 发表于 2020年8月15日 16:25:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/63424055.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定