如何设置Spring Boot来运行HTTPS / HTTP端口

时间:2015-06-17 15:39:56

标签: java spring spring-boot ssl

Spring boot具有一些配置Web端口和SSL设置的属性,但是一旦设置了SSL证书,http端口就变成了https端口。

那么,如何在其上运行两个端口,例如:80和443同时运行?

如您所见,只有一个端口的属性,在这种情况下启用了“server.ssl”,这使得http端口自动被禁用。

##############
### Server ###
##############
server.port=9043
server.session-timeout=1800
server.ssl.key-store=file:///C:/Temp/config/localhost.jks
server.ssl.key-store-password=localhost
server.ssl.key-password=localhost
server.ssl.trust-store=file:///C:/Temp/config/localhost.jks
server.ssl.trust-store-password=localhost

我正在尝试使用Tomcat或Undertow。我很感激任何帮助!

6 个答案:

答案 0 :(得分:37)

使用属性的Spring Boot配置,只允许配置一个连接器。你需要的是多个连接器,为此你必须编写一个Configuration类。按照

中的说明操作

https://docs.spring.io/spring-boot/docs/1.2.3.RELEASE/reference/html/howto-embedded-servlet-containers.html

您可以找到一个通过属性配置https的工作示例,然后通过下面的http://wwwServletContainerCustomizer来查找http

http://izeye.blogspot.com/2015/01/configure-http-and-https-in-spring-boot.html?showComment=1461632100718#c4988529876932015554

server:
  port:
    8080
  ssl:
    enabled:
      true
    keyStoreType:
      PKCS12
    key-store:
      /path/to/keystore.p12
    key-store-password:
      password
  http:
    port:
      8079
@Configuration
public class TomcatConfig {

@Value("${server.http.port}")
private int httpPort;

@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
    return new EmbeddedServletContainerCustomizer() {
        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {
            if (container instanceof TomcatEmbeddedServletContainerFactory) {
                TomcatEmbeddedServletContainerFactory containerFactory =
                        (TomcatEmbeddedServletContainerFactory) container;

                Connector connector = new Connector(TomcatEmbeddedServletContainerFactory.DEFAULT_PROTOCOL);
                connector.setPort(httpPort);
                containerFactory.addAdditionalTomcatConnectors(connector);
            }
        }
    };
}
}

答案 1 :(得分:17)

当前接受的答案可以很好地工作,但是如果您希望它与Spring Boot 2.0.0及更高版本一起使用,则需要进行一些调整:

@Component
public class HttpServer {
  @Bean
  public ServletWebServerFactory servletContainer(@Value("${server.http.port}") int httpPort) {
      Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
      connector.setPort(httpPort);

      TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
      tomcat.addAdditionalTomcatConnectors(connector);
      return tomcat;
  }
}

或kotlin版本:

@Component
class HttpServer {
  @Bean
  fun servletContainer(@Value("\${server.http.port}") httpPort: Int): ServletWebServerFactory {
    val connector = Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL)
    connector.setPort(httpPort)

    val tomcat = TomcatServletWebServerFactory()
    tomcat.addAdditionalTomcatConnectors(connector)
    return tomcat
  }
}

答案 2 :(得分:4)

Bellow是一个简单的示例,说明如何启用两个HTTP / HTTPS端口。

Spring Boot只允许按配置打开一个端口。必须以编程方式打开第二个端口。

首先以编程方式打开HTTP端口。

import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;

@Configuration
public class UndertowConfig {

@Value("${server.http.port}")
private int httpPort;

@Value("${server.http.interface}")
private String httpInterface;

@Bean
public WebServerFactoryCustomizer<UndertowServletWebServerFactory> containerCustomizer() {
    return (WebServerFactoryCustomizer) factory -> {
        UndertowServletWebServerFactory undertowFactory = (UndertowServletWebServerFactory) factory;
        undertowFactory.getBuilderCustomizers().add(builder -> {
            builder.addHttpListener(httpPort, httpInterface);
        });
    };
}

}

HTTPS by configuration

Spring可以从可用属性源打开HTTP或HTTPS端口读取属性。如果您添加适当的配置,如下所示,将HTTPs端口打开就足够了。

#default secured port (Spring will open it automatically)
server.port=8443
#additional HTTP port (will open it in UndertowConfig)
server.http.port=8080
#Open to the world
server.http.interface=0.0.0.0
#These settings tell Spring to open SSL port
server.ssl.keystore=file:${APP_BASE}/conf/server/ssl_selfsigned/server.keystore
server.ssl.key-store-password=xyz
server.ssl.key-password=xyz
通过手动设置

HTTPS

如果您愿意,可以像打开HTTP端口一样打开另一个SSL端口

 .addHttpsListener(ssl_port, httpInterface, getSSLContext());

这是您创建SSL上下文的方法

import javax.net.ssl.*;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyStore;

public SSLContext getSSLContext() throws Exception
{
    return createSSLContext(loadKeyStore(serverKeystore,keyStorePassword),
            loadKeyStore(serverTruststore,trustStorePassword));

}


private SSLContext createSSLContext(final KeyStore keyStore,
                                    final KeyStore trustStore) throws Exception {

    KeyManager[] keyManagers;
    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    keyManagerFactory.init(keyStore, keyStorePassword.toCharArray());
    keyManagers = keyManagerFactory.getKeyManagers();

    TrustManager[] trustManagers;
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    trustManagerFactory.init(trustStore);
    trustManagers = trustManagerFactory.getTrustManagers();

    SSLContext sslContext;
    sslContext = SSLContext.getInstance("TLS");
    sslContext.init(keyManagers, trustManagers, null);

    return sslContext;
}


private static KeyStore loadKeyStore(final String storeLoc, final String storePw) throws Exception {
    InputStream stream = Files.newInputStream(Paths.get(storeLoc));
    if(stream == null) {
        throw new IllegalArgumentException("Could not load keystore");
    }
    try(InputStream is = stream) {
        KeyStore loadedKeystore = KeyStore.getInstance("JKS");
        loadedKeystore.load(is, storePw.toCharArray());
        return loadedKeystore;
    }
}

答案 3 :(得分:2)

另一个Spring boot 2.x解决方案:

private static final int HTTP_PORT = 80;
private static final int HTTPS_PORT = 443;
private static final String HTTP = "http";
private static final String USER_CONSTRAINT = "CONFIDENTIAL";

@Bean
public ServletWebServerFactory servletContainer() {
    TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
        @Override
        protected void postProcessContext(Context context) {
            SecurityConstraint securityConstraint = new SecurityConstraint();
            securityConstraint.setUserConstraint(USER_CONSTRAINT);
            SecurityCollection collection = new SecurityCollection();
            collection.addPattern("/*");
            securityConstraint.addCollection(collection);
            context.addConstraint(securityConstraint);
        }
    };
    tomcat.addAdditionalTomcatConnectors(redirectConnector());
    return tomcat;
}

private Connector redirectConnector() {
    Connector connector = new Connector(
            TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
    connector.setScheme(HTTP);
    connector.setPort(HTTP_PORT);
    connector.setSecure(false);
    connector.setRedirectPort(HTTPS_PORT);
    return connector;
}

并在您的属性中设置 server.port = 443

答案 4 :(得分:1)

看看:https://github.com/creactiviti/spring-boot-starter-acme。它使得自动生成基于LetsEncrypt的SSL证书非常容易。

来自自述文件:

  1. 将模块作为依赖项添加到pom.xml文件中。

  2. 构建您的项目。

  3. 将其部署到目标计算机并将您的域名指向该计算机的IP地址。 LetsEncrypt通过回调此模块公开的http://your-domain/.well-known/acme-challenge/ {token}端点来验证您对域的所有权。

  4. 确保您的服务器的$ PATH上有openssl。

  5. 要激活spring-boot-starter-acme并生成证书执行:

    sudo java -Dserver.port=80 -Dacme.enabled=true -Dacme.domain-name=<YOUR_DOMAIN_NAME> -Dacme.accept-terms-of-service=true -jar mysecureapp-0.0.1-SNAPSHOT.jar

  6. 检查控制台是否已成功生成证书。

  7. 停止您的应用程序并将其配置为使用生成的证书:

    server.port=443 server.ssl.key-store=keystore.p12 server.ssl.key-store-password=password server.ssl.keyStoreType=PKCS12

答案 5 :(得分:0)

最重要的答案都是很好的,而且可能有用,但是我一直在将Undertow与JHipster结合使用,因此它们对我不起作用(这是主要的search结果)。 this issue中具体提到了Undertow的正确代码:

@Bean
public UndertowServletWebServerFactory embeddedServletContainerFactory() {
    UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
    factory.addBuilderCustomizers(new UndertowBuilderCustomizer() {
        @Override
        public void customize(Undertow.Builder builder) {
            builder.addHttpListener(8080, "0.0.0.0");
        }
    });
    return factory;
}