Spring Boot 中的 SSL 证书

Posted

技术标签:

【中文标题】Spring Boot 中的 SSL 证书【英文标题】:SSL Certificate in Spring Boot 【发布时间】:2014-11-25 13:57:13 【问题描述】:

我有证书文件 xx.crt 和 xx.pfx。我也有 xx.pfx 的密码。如何配置这个 Spring Boot 嵌入式 tomcat?

    Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
    Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
    connector.setScheme("https");
    connector.setSecure(true);
    protocol.setSSLEnabled(true);
    protocol.setKeystoreFile(??);
    protocol.setKeyPass(??);
    protocol.setTruststoreFile(??);
    return connector;

【问题讨论】:

【参考方案1】:

在 Spring Boot 中使用 .pfx 文件的最简单方法。 请按照以下步骤使其工作。 1) 从服务提供商处获取 pfx 文件。 2) 安装证书。如何安装证书请参考link。

application.properties

server.port= 9091
server.ssl.trust-store= classpath:jks/Test_Certificate.pfx
server.ssl.trust-store-password= XXXXXX
server.ssl.enabled= false
server.ssl.trust-store-type= PKCS12
soap.url=https://localost:8080/test/Calculator.wsdl

TestClientConfiguration.java

import java.io.IOException;
import java.security.KeyStore;

import javax.net.ssl.SSLContext;

import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContexts;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.transport.http.HttpComponentsMessageSender;

@Configuration
public class TestClientConfiguration 

    private final String SOAP_URI = "https://localost:8080/test/Calculator.wsdl";

    @Value("$server.ssl.trust-store")
    private Resource trustStore;

    @Value("$server.ssl.trust-store-password")
    private String trustStorePassword;

    @Value("$server.ssl.trust-store-type")
    private String trustStoreType;

    @Bean
    public TestServiceClient processMessage(Jaxb2Marshaller marshaller) throws Exception 
        TestServiceClient client = new TestServiceClient();
        client.setDefaultUri(SOAP_URI);
        client.setMarshaller(marshaller);
        client.setUnmarshaller(marshaller);
        client.setMessageSender(httpComponentsMessageSender());
        return client;
    

    @Bean
    Jaxb2Marshaller jaxb2Marshaller() 
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        jaxb2Marshaller.setContextPath("com.test.soap.types");

        return jaxb2Marshaller;
    

    @Bean
    public HttpComponentsMessageSender httpComponentsMessageSender() throws Exception 
        HttpComponentsMessageSender httpComponentsMessageSender = new HttpComponentsMessageSender();
        httpComponentsMessageSender.setHttpClient(httpClient());
        return httpComponentsMessageSender;
    

    public HttpClient httpClient() throws Exception 
        KeyStore keyStore = KeyStore.getInstance(trustStoreType);
        keyStore.load(trustStore.getInputStream(), trustStorePassword.toCharArray());

        SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(keyStore, trustStorePassword.toCharArray())
                .build();

        HttpClient httpClient = HttpClients.custom().setSSLContext(sslContext)
                .addInterceptorFirst(new ContentLengthHeaderRemover()).build();
        return httpClient;
    


TestServiceClient.java

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.client.core.WebServiceMessageCallback;
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
import org.springframework.ws.soap.SoapHeader;
import org.springframework.ws.soap.SoapMessage;

@Qualifier("testSoapServiceClient")
public class TestServiceClient extends WebServiceGatewaySupport 
    @Value("$soap.url")
    private String testsoapurl;

    public String processMessage(String mgRequest, Message reqHeader) 

        StreamSource source = new StreamSource(new StringReader(mgRequest));
        StringWriter stringWriter = new StringWriter();
        StreamResult result = new StreamResult(stringWriter);
        getWebServiceTemplate().sendSourceAndReceiveToResult(testsoapurl, source, new WebServiceMessageCallback() 

            @Override
            public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException 
                try 
                    SoapMessage soapMessage = (SoapMessage) message;

                    //Soap Actio
                    soapMessage.setSoapAction("urn:test/ProcessMessage");

                    // get the header from the SOAP message
                    SoapHeader soapHeader = soapMessage.getSoapHeader();

                    // create the header element
                    ObjectFactory factory = new ObjectFactory();
                    JAXBElement<Message> headerMessage = factory.createMessage(reqHeader);

                    // create a marshaller
                    JAXBContext context = JAXBContext.newInstance(Message.class);
                    Marshaller marshaller = context.createMarshaller();

                    // marshal the headers into the specified result
                    marshaller.marshal(headerMessage, soapHeader.getResult());
                 catch (Exception e) 
                    /////
                
            

        , result);
        return stringWriter.toString();
    


【讨论】:

【参考方案2】:

解决此问题最简单的方法是使用 keytool(Windows 上的 keytool.exe)将 PFX 文件转换为 JKS:

keytool -importkeystore -srckeystore mypfxfile.pfx -srcstoretype pkcs12 -destkeystore newkeystore.jks -deststoretype JKS

并使用protocol.setKeystoreFile()protocol.setKeyPass() 加载它。

【讨论】:

【参考方案3】:

如果您查看Http11NioProtocol 这些方法采用字符串参数...无论如何这里是一个相关的问题/答案How can I specify my .keystore file with Spring Boot and Tomcat?

【讨论】:

我已经阅读了所有文档和 *** 问题。它部分有效,但是当将证书复制到生产盒时,它会弄乱一些格式并再次给出 IO 异常。这个问题也可以在 stacktrace 上轻松找到。可能是关键应该包括标准文档中的 keytool 转换(下面接受的答案)。

以上是关于Spring Boot 中的 SSL 证书的主要内容,如果未能解决你的问题,请参考以下文章

spring boot ssl 客户端证书失败,PKIX 路径构建失败错误

无法获得 go daddy ssl 证书以使用 spring boot

无法使用 Spring Boot 连接到具有多个 SSL 证书的多个 IBM MQ 通道

Spring Boot使用阿里云证书启用HTTPS

如何配置 Spring Boot 应用程序以接受未知的 SSL 客户端证书?

Https系列之二:https的SSL证书在服务器端的部署,基于tomcat,spring boot