1. 程式人生 > >Https系列之三:讓服務器同時支持http、https,基於spring boot

Https系列之三:讓服務器同時支持http、https,基於spring boot

signed 默認 gfs proc idl clas 兩種方法 .... gpg

Https系列會在下面幾篇文章中分別作介紹:

一:https的簡單介紹及SSL證書的生成
二:https的SSL證書在服務器端的部署,基於tomcat,spring boot
三:讓服務器同時支持http、https,基於spring boot
四:https的SSL證書在Android端基於okhttp,Retrofit的使用

所有文章會優先在:
微信公眾號“顏家大少”中發布
轉載請標明出處


前面已介紹了:”https在服務器端的部署,基於tomcat,spring boot“
但我們會發現一個問題,只能用https登錄我們的網站,而不能用http

假設我們的網站名為:www.my.com
如果是之前的http,我們只需在瀏覽器中輸入:my.com
瀏覽器就會自動登錄到:http:// www.my.com
但部署了https後,發現在瀏覽器中輸入:my.com,返回的結果是:無法訪問此網站
這對用戶來說,體驗是非常不好的。

好吧,那我們試試一些比較有名的網站,如阿裏雲。
在瀏覽器中輸入:aliyun.com
就能自動跳轉到:https: //www.aliyun.com

那我們能不能在部署了https後,在輸入:my.com
自動跳轉到https對應的: https:// www.my.com

依然跳轉到:http:// www.my.com ?

答案是,上面兩種方法都可以的,任君選擇

下面介紹的就是以上要求基於spring boot的實現

直接上代碼:

import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class ServerMain implements CommandLineRunner{    
    @Bean
    public EmbeddedServletContainerFactory servletContainer() {
        TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                //Due to CONFIDENTIAL and /*, this will cause Tomcat to redirect every request to HTTPS. 
                //You can configure multiple patterns and multiple constraints if you need more control over what is and is not redirected.

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

  }
    @Bean
    public Connector httpConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");

        //Set the scheme that will be assigned to requests received through this connector
        //@param scheme The new scheme
        connector.setScheme("http");

        //Set the port number on which we listen for requests.
        // @param port The new port number
        connector.setPort(80);       

        //Set the secure connection flag that will be assigned to requests received through this connector.
        //@param secure The new secure connection flag
        //if connector.setSecure(true),the http use the http and https use the https;else if connector.setSecure(false),the http redirect to https;
        connector.setSecure(false);

        //redirectPort The redirect port number (non-SSL to SSL)
        connector.setRedirectPort(443);
        return connector;
    }

    public static void main(String[] args) throws Exception {            
        SpringApplication.run(ServerMain.class, args);
    }
    @Override
    public void run(String... arg0) throws Exception {
        // TODO Auto-generated method stub
    }

}

其中,下面代碼的作用是把此EmbeddedServletContainerFactory 註入到web容器中

@Bean
public EmbeddedServletContainerFactory servletContainer()

然後,用下面的代碼攔截所有的/*請求

@Override
protected void postProcessContext(Context context) {
..........
    constraint.setUserConstraint("CONFIDENTIAL");
    collection.addPattern("/*");
.............
}

並把其關聯到下面的httpConnector中

@Bean
public Connector httpConnector()

最後,在public Connector httpConnector()中,
把http設為默認的80端口,並把http的請求跳轉到443的https端口
其中443是https的默認端口,也可以設為其它的值,但要和resources/application.properties的內容對應
如下:

server.port=443
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=123456
server.ssl.keyStoreType=PKCS12
server.ssl.keyAlias:tomcat

運行服務器,會看到打印如下:
技術分享
其中會看到TomcatEmbeddedServletContainer,和同時開啟的兩個端口:443 (https) 80 (http)

TomcatEmbeddedServletContainer : Tomcat started on port(s): 443 (https) 80 (http)

Ok,那現在試試輸入:my.com,就會發現瀏覽器會直接跳到:https:// www.my.com了

到此,這件事情就算是大功告成了。

但此時有同學可能會提出特殊的要求:
他的https只是為了某某的要求而使用的,比如說要接入什麽什麽的一定要填的是https的地址
而他的網站根本就不需要https這種安全級別的,另外,他覺得http的訪問速度可能會快點,你知到有些同學是有這種潔癖的 :p
也就是說:
輸入:my.com,跳到: http:// www.my.com
輸入:https:// www.my.com,跳到:https:// www.my.com
要實現此要求,其實很簡單,只需要把:

@Bean
public Connector httpConnector() {
........
connector.setSecure(false);
...........

改為

@Bean
public Connector httpConnector() {
........
connector.setSecure(true);
...........

就大功告成了
更多內容請看:Https系列之四:https的SSL證書在Android端基於okhttp,Retrofit的使用


更多內容,請關註微信公眾號:顏家大少
技術分享

?

Https系列之三:讓服務器同時支持http、https,基於spring boot