You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 3双向TLS配置:如何指定.p12文件内容而非路径

在Spring Boot 3中使用P12文件内容配置双向TLS

问题背景

在Spring Boot 2中配置双向TLS,需设置以下属性并配合手动配置:

ssl.keystore=
ssl.keystore-password=
ssl.truststore=
ssl.truststore-password=

Spring Boot 3简化了配置,只需设置以下属性即可完成基础双向TLS配置,无需额外手动配置:

server.ssl.key-store=file:keystore.p12
server.ssl.key-store-password=password
server.ssl.key-store-type=PKCS12
server.ssl.key-password=password
server.ssl.trust-store-password=password
server.ssl.trust-store=file:truststore.p12
server.ssl.client-auth=want

当前需求是直接指定.p12文件的内容而非文件路径来完成配置,可通过以下两种方式实现:


方式一:自定义SslStoreProvider(推荐)

Spring Boot 3提供了SslStoreProvider接口,可自定义密钥库和信任库的加载逻辑,直接从字节数组加载P12内容:

import org.springframework.boot.ssl.SslStoreBundle;
import org.springframework.boot.ssl.SslStoreProvider;
import org.springframework.stereotype.Component;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import java.io.ByteArrayInputStream;
import java.security.KeyStore;

@Component
public class ByteArraySslStoreProvider implements SslStoreProvider {

    // 实际场景中可从环境变量、配置中心获取Base64编码的P12内容并解码
    private final byte[] keystoreBytes = loadBase64EncodedContent(System.getenv("KEYSTORE_BASE64"));
    private final byte[] truststoreBytes = loadBase64EncodedContent(System.getenv("TRUSTSTORE_BASE64"));
    private final String keystorePassword = System.getenv("KEYSTORE_PASSWORD");
    private final String truststorePassword = System.getenv("TRUSTSTORE_PASSWORD");
    private final String keyPassword = System.getenv("KEY_PASSWORD");

    @Override
    public SslStoreBundle getStores() {
        try {
            // 加载密钥库
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            keyStore.load(new ByteArrayInputStream(keystoreBytes), keystorePassword.toCharArray());

            // 加载信任库
            KeyStore trustStore = KeyStore.getInstance("PKCS12");
            trustStore.load(new ByteArrayInputStream(truststoreBytes), truststorePassword.toCharArray());

            return SslStoreBundle.of(
                    keyStore, keystorePassword.toCharArray(), keyPassword.toCharArray(),
                    trustStore, truststorePassword.toCharArray()
            );
        } catch (Exception e) {
            throw new RuntimeException("加载SSL证书存储失败", e);
        }
    }

    // 解码Base64编码的P12内容
    private byte[] loadBase64EncodedContent(String base64Content) {
        if (base64Content == null || base64Content.isEmpty()) {
            throw new IllegalArgumentException("P12内容不能为空");
        }
        return java.util.Base64.getDecoder().decode(base64Content);
    }
}

说明

  • 自定义SslStoreProvider会被Spring Boot自动检测并使用,无需配置server.ssl.key-store和server.ssl.trust-store路径属性。
  • 建议将P12内容以Base64编码形式存储在环境变量或加密配置中心,避免明文泄露。

方式二:自定义Tomcat容器配置(针对Tomcat场景)

如果使用Tomcat作为嵌入式容器,可通过WebServerFactoryCustomizer直接配置连接器的SSL参数:

import org.apache.catalina.connector.Connector;
import org.apache.coyote.http11.Http11NioProtocol;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import java.io.ByteArrayInputStream;
import java.security.KeyStore;

@Component
public class TomcatSslCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {

    private final byte[] keystoreBytes = loadBase64EncodedContent(System.getenv("KEYSTORE_BASE64"));
    private final byte[] truststoreBytes = loadBase64EncodedContent(System.getenv("TRUSTSTORE_BASE64"));
    private final String keystorePassword = System.getenv("KEYSTORE_PASSWORD");
    private final String truststorePassword = System.getenv("TRUSTSTORE_PASSWORD");
    private final String keyPassword = System.getenv("KEY_PASSWORD");

    @Override
    public void customize(TomcatServletWebServerFactory factory) {
        factory.addConnectorCustomizers((Connector connector) -> {
            Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
            protocol.setSSLEnabled(true);
            connector.setSecure(true);
            connector.setScheme("https");

            try {
                // 加载密钥库
                KeyStore keyStore = KeyStore.getInstance("PKCS12");
                keyStore.load(new ByteArrayInputStream(keystoreBytes), keystorePassword.toCharArray());
                KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
                keyManagerFactory.init(keyStore, keyPassword.toCharArray());

                // 加载信任库
                KeyStore trustStore = KeyStore.getInstance("PKCS12");
                trustStore.load(new ByteArrayInputStream(truststoreBytes), truststorePassword.toCharArray());
                TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                trustManagerFactory.init(trustStore);

                // 配置SSL参数
                protocol.setKeyManagers(keyManagerFactory.getKeyManagers());
                protocol.setTrustManagers(trustManagerFactory.getTrustManagers());
                protocol.setClientAuth("want"); // 对应双向TLS的客户端认证策略
            } catch (Exception e) {
                throw new RuntimeException("配置Tomcat SSL失败", e);
            }
        });
    }

    private byte[] loadBase64EncodedContent(String base64Content) {
        if (base64Content == null || base64Content.isEmpty()) {
            throw new IllegalArgumentException("P12内容不能为空");
        }
        return java.util.Base64.getDecoder().decode(base64Content);
    }
}

说明

  • 该方式直接操作Tomcat的连接器,适合需要更细粒度控制SSL配置的场景。
  • 若使用Jetty或Undertow容器,可参考对应容器的SSL扩展API实现类似逻辑。

注意事项

  • 确保密钥库、信任库的密码和密钥密码与P12文件一致,否则会导致SSL加载失败。
  • 生产环境中务必对P12内容和密码进行加密存储,避免明文暴露。

内容的提问来源于stack exchange,提问作者Anthony Vinay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 02:40:06