前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Springboot 自定义 HTTPS 的几种方式

Springboot 自定义 HTTPS 的几种方式

原创
作者头像
鲍远林
修改2022-04-26 09:08:12
1.1K0
修改2022-04-26 09:08:12
举报
文章被收录于专栏:TPlusTPlus

虽然 Springboot 提供了相关参数用来启用 HTTPS 及相关配置,但在有些场景下需要我们做些定制化才能结合实际很好的启用 HTTPS 功能。比如,在我司有专门的秘钥系统来托管ssl证书及秘钥。此时,就不能简单的使用 server.ssl.xxx 来开启 HTTPS 了,而是需要先从秘钥系统下载 ssl 证书及秘钥,然后才能打开 springboot 的 HTTPS 功能。下面针对这种情况介绍下 springboot 中定制 https 的几种方式。

方式一:ServletWebServerFactory

代码语言:java
复制
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(DemoHttpsProperties.class)
@ConditionalOnExpression("${demo.ssl.enabled}")
public class TomcatHttpsConfiguration {

    @Resource
    private DemoHttpsProperties demoHttpsProperties;

    @Bean
    public ServletWebServerFactory servletContainer() throws Exception {

        // 获取 key-store 密码, 下载SSL证书并进行校验
        String keyStorePassword = getKeyStorePassword();
        String keyStoreFile = downloadKeyStore();
        verifyCertificate(keyStoreFile, keyStorePassword);

        log.info("create TomcatServletWebServerFactory");
        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                SecurityConstraint securityConstraint = new SecurityConstraint();
                securityConstraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                securityConstraint.addCollection(collection);
                context.addConstraint(securityConstraint);
            }
        };

        // 添加 SSL Connector
        factory.addConnectorCustomizers(connector -> {
            connector.setPort(demoHttpsProperties.getPort());
            connector.setSecure(true);
            connector.setScheme("https");
            Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
            protocol.setSSLEnabled(true);
            protocol.setKeystoreFile(keyStoreFile);
            protocol.setKeystorePass(keyStorePassword);
            protocol.setKeystoreType(demoHttpsProperties.getKeyStoreType());
            protocol.setKeyAlias(demoHttpsProperties.getKeyAlias());
            protocol.setSslProtocol("TLSv1.2");
            protocol.setSslEnabledProtocols("TLSv1.2+TLSv1.3");
            protocol.setClientAuth("false");
        });
        return factory;
    }

    private void verifyCertificate(String keyStoreFile, String password) throws Exception {
        KeyStore ks = KeyStore.getInstance(demoHttpsProperties.getKeyStoreType());
        FileInputStream fis = new FileInputStream(keyStoreFile);
        ks.load(fis, password.toCharArray());
        fis.close();
        X509Certificate x509Certificate = (X509Certificate) ks.getCertificate(demoHttpsProperties.getKeyAlias());
        x509Certificate.checkValidity();
    }

    private String downloadKeyStore(KeyApi keyApi){
        ...
    }

    private String getKeyStorePassword() {
        ...
    }
}

这种方式下,如果想做成 autoconfig 需要禁止 springboot web 的自动配置,否则启动时会出现多个 tomcat 的错误,可用以下两种方式解决:

  • @SpringBootApplication(exclude = ServletWebServerFactoryAutoConfiguration.class)
  • 或者配置文件中添加:spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration

方式二:WebServerFactoryCustomizer

代码语言:java
复制
public class TomcatWebServerCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {

    public TomcatWebServerCustomizer(DemoHttpsProperties props) throws Exception {

        // 获取 key-store 密码, 下载SSL证书并进行校验
        this.keyStoreType = props.getKeyStoreType();
        this.keyAlias = props.getKeyAlias();
        this.keyStorePassword = getKeyStorePassword();
        this.keyStoreFile = downloadKeyStore();
        verifyCertificate(this.keyStoreFile, this.keyStoreType, this.keyStorePassword);
    }

    @Override
    public void customize(TomcatServletWebServerFactory factory) {

        factory.addConnectorCustomizers(connector -> {
            connector.setSecure(true);
            connector.setScheme("https");
            Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
            protocol.setSSLEnabled(true);
            protocol.setKeystoreFile(keyStoreFile);
            protocol.setKeystorePass(keyStorePassword);
            protocol.setKeystoreType(keyStoreType);
            protocol.setKeyAlias(keyAlias);
            protocol.setSslProtocol("TLSv1.2");
            protocol.setSslEnabledProtocols("TLSv1.2+TLSv1.3");
            protocol.setClientAuth("false");
        });
    }

    private void verifyCertificate(String keyStoreFile, String keyStoreType, String keyStorePwd) throws Exception {
        KeyStore ks = KeyStore.getInstance(keyStoreType);
        FileInputStream fis = new FileInputStream(keyStoreFile);
        ks.load(fis, keyStorePwd.toCharArray());
        fis.close();
        X509Certificate x509Certificate = (X509Certificate) ks.getCertificate(keyAlias);
        x509Certificate.checkValidity();
    }

    private String downloadKeyStore() {
        ...
    }

    private String getKeyStorePassword() {
        ...
    }
}

方式三:重定向

网上见到最多的就是这种方式,同时启用 http 和 https 端口,将 http 请求重定向到 https,具体如下:

代码语言:java
复制
@Configuration
public class HttpsConfig {
    @Bean
    public TomcatServletWebServerFactory servletContainer() {

        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {

            @Override
            protected void postProcessContext(Context context) {

                SecurityConstraint securityConstraint = new SecurityConstraint();
                securityConstraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                securityConstraint.addCollection(collection);
                context.addConstraint(securityConstraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(initiateHttpConnector());
        return tomcat;
    }

    private Connector initiateHttpConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        connector.setPort(8080);
        connector.setSecure(true);
        connector.setRedirectPort(443);
        return connector;
    }
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
作者已关闭评论
0 条评论
热度
最新
推荐阅读
目录
  • 方式一:ServletWebServerFactory
  • 方式二:WebServerFactoryCustomizer
  • 方式三:重定向
相关产品与服务
SSL 证书
腾讯云 SSL 证书(SSL Certificates)为您提供 SSL 证书的申请、管理、部署等服务,为您提供一站式 HTTPS 解决方案。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档