1

tomcat方案配置

证书生成:使用jdk提供的keytool命令,例如:

keytool -genkeypair -alias "tomcat" -keyalg "RSA" -keystore "E:\tomcat.keystore"  

非springboot项目

修改tomcat下conf/server.xml,加入:

<Connector SSLEnabled="true" acceptCount="100" clientAuth="false" URIEncoding="UTF-8"
    disableUploadTimeout="true" enableLookups="false" maxThreads="25"
    port="8443" keystoreFile="E:\tomcat.keystore" keystorePass="123456"
    protocol="org.apache.coyote.http11.Http11NioProtocol" scheme="https"
    secure="true" sslProtocol="TLS" />

其中keystoreFile为证书存放路径,keystorePass为证书密码

springboot项目

修改application.yml文件:

server.port: 8443 #https端口
server.ssl.key-store: E:/keystore.p12  #证书路径
server.ssl.key-store-password: 123456  #证书密码
server.ssl.keyStoreType: PKCS12
server.ssl.keyAlias: tomcat
http.port: 8080#http端口

上述配置包含http端口8080和https端口8443

若要既支持http请求又支持https请求,则需要添加类如下:

@Configuration
public class HttpSupport {
    @Value("${http.port}")
    private int port;

    @Bean
    public EmbeddedServletContainerFactory servletContainer() {
        TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
        tomcat.addAdditionalTomcatConnectors(createHttpConnector());
        return tomcat;
    }

    private Connector createHttpConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        connector.setPort(port);
        connector.setSecure(false);
        return connector;
    }
}

如果只支持https请求的话可以考虑将http请求强转成https,需添加类如下:

@Configuration
public class HttpsConfiguration {
    @Value("${http.port}")
    private int httpPort;
    @Value("${server.port}")
    private int httpsPort;
    @Bean
    public EmbeddedServletContainerFactory servletContainer() {
        TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory() {
            @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(httpPort);
        connector.setSecure(false);
        connector.setRedirectPort(httpsPort);
        return connector;
    }
}

nginx方案配置

证书生成:使用openssl命令
修改nginx.conf文件:

server {
        listen 443;
        server_name  localhost;
        ssl                  on;
        ssl_certificate      D:/nginx/ssl/lee.crt;
        ssl_certificate_key  D:/nginx/ssl/lee.key;
        ssl_session_cache    shared:SSL:10m;
        ssl_session_timeout  5m;
        ssl_protocols  SSLv3 TLSv1;
        ssl_ciphers  HIGH:!ADH:!EXPORT56:RC4+RSA:+MEDIUM;
        ssl_prefer_server_ciphers   on;
       
        location / {
            proxy_pass http://xxx.xx.x.xx:8080;
            proxy_set_header Host $host;
            proxy_set_header X-Real-Ip $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
         
    }

修改server.xml配置,在模块下添加:

<Valve className="org.apache.catalina.valves.RemoteIpValve"  
    remoteIpHeader="X-Forwarded-For"  
    protocolHeader="X-Forwarded-Proto"  
    protocolHeaderHttpsValue="https"/>

注意:由于反向代理用了7层转发,所以:

request.getScheme()  //总是 http,而不是实际的http或https  
request.isSecure()  //总是false(因为总是http)  
request.getRemoteAddr()  //总是 nginx 请求的 IP,而不是用户的IP  
request.getRequestURL()  //总是 nginx 请求的URL 而不是用户实际请求的 URL  
response.sendRedirect( 相对url )  //总是重定向到 http 上 (因为认为当前是 http 请求)  

解决方案为:如上nginx和tomcat配置

proxy_set_header Host $host;
proxy_set_header X-Real-Ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
<Valve className="org.apache.catalina.valves.RemoteIpValve"  
    remoteIpHeader="X-Forwarded-For"  
    protocolHeader="X-Forwarded-Proto"  
    protocolHeaderHttpsValue="https"/>

通常在反向代理那边配X-Forwarded-For,Tomcat这边用request.getHeader("X-Forwarded-For")拿到用户真实IP地址。在反向代理那边配X-Forwarded-Proto这种Header,Tomcat这边用request.getHeader("X-Forwarded-Proto")来判断用户是否处于https状态。


pysasuke
199 声望4 粉丝

青铜分段掌控雷电