如何设置 Spring 引导至 运行 HTTPS/HTTP 端口
How set up Spring Boot to run HTTPS / HTTP ports
Spring 启动有一些属性来配置 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。如果有任何帮助,我将不胜感激!
Spring 使用属性启动配置,只允许配置一个连接器。您需要的是多个连接器,为此,您必须编写配置 class。按照
中的说明进行操作
您可以在下面找到一个通过属性配置 HTTPS,然后通过 EmbeddedServletContainerCustomizer 配置 HTTP 的工作示例
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);
}
}
};
}
}
Bellow 是一个简单的示例,说明如何为 undertow 启用两个 HTTP/HTTPS 端口。
Spring 开机只允许通过配置打开一个端口。必须以编程方式打开第二个端口。
首先以编程方式打开 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 配置
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;
}
}
看看:https://github.com/creactiviti/spring-boot-starter-acme。这使得 auto-generate 基于 LetsEncrypt 的 SSL 证书变得非常容易。
来自自述文件:
将模块作为依赖项添加到 pom.xml 文件。
构建您的项目。
将其部署到目标机器并将您的域名指向该机器的 IP 地址。 LetsEncrypt 通过回调此模块公开的 http://your-domain/.well-known/acme-challenge/{token} 端点来验证您对域的所有权。
确保您的服务器在其 $PATH 上有可用的 openssl。
激活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
检查您的控制台以确认证书已成功生成。
停止您的应用程序并将其配置为使用生成的证书:
server.port=443
server.ssl.key-store=keystore.p12
server.ssl.key-store-password=password
server.ssl.keyStoreType=PKCS12
当前接受的答案完美无缺,但如果您希望它与 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
}
}
另一个Spring启动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
最重要的答案都很棒并且可能有效,但我一直在将 Undertow 与 JHipster 一起使用,所以它们对我不起作用(这是主要的 search result). The right code for Undertow is mentioned in this issue 特别是:
@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;
}
Spring 启动有一些属性来配置 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。如果有任何帮助,我将不胜感激!
Spring 使用属性启动配置,只允许配置一个连接器。您需要的是多个连接器,为此,您必须编写配置 class。按照
中的说明进行操作您可以在下面找到一个通过属性配置 HTTPS,然后通过 EmbeddedServletContainerCustomizer 配置 HTTP 的工作示例
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);
}
}
};
}
}
Bellow 是一个简单的示例,说明如何为 undertow 启用两个 HTTP/HTTPS 端口。
Spring 开机只允许通过配置打开一个端口。必须以编程方式打开第二个端口。
首先以编程方式打开 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 配置
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;
}
}
看看:https://github.com/creactiviti/spring-boot-starter-acme。这使得 auto-generate 基于 LetsEncrypt 的 SSL 证书变得非常容易。
来自自述文件:
将模块作为依赖项添加到 pom.xml 文件。
构建您的项目。
将其部署到目标机器并将您的域名指向该机器的 IP 地址。 LetsEncrypt 通过回调此模块公开的 http://your-domain/.well-known/acme-challenge/{token} 端点来验证您对域的所有权。
确保您的服务器在其 $PATH 上有可用的 openssl。
激活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
检查您的控制台以确认证书已成功生成。
停止您的应用程序并将其配置为使用生成的证书:
server.port=443 server.ssl.key-store=keystore.p12 server.ssl.key-store-password=password server.ssl.keyStoreType=PKCS12
当前接受的答案完美无缺,但如果您希望它与 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
}
}
另一个Spring启动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
最重要的答案都很棒并且可能有效,但我一直在将 Undertow 与 JHipster 一起使用,所以它们对我不起作用(这是主要的 search result). The right code for Undertow is mentioned in this issue 特别是:
@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;
}