Java 如何设置 Spring Boot 以运行 HTTPS/HTTP 端口
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30896234/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How set up Spring Boot to run HTTPS / HTTP ports
提问by Carlos Alberto
Spring boot have some properties to config web port and SSL settings, but once a SSL certificate is set the http port turns into https port.
Spring boot 有一些属性来配置 web 端口和 SSL 设置,但是一旦设置了 SSL 证书,http 端口就会变成 https 端口。
So, how can I keep both ports running on it, for example: 80 an 443 at the same time?
那么,如何让两个端口同时运行,例如:80 和 443?
As you can see, there only properties for one port, in this case "server.ssl" is enabled, what makes http port be disabled automatically.
如您所见,只有一个端口的属性,在这种情况下启用了“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
I am trying to use even Tomcat or Undertow. I'd appreciate any help!
我什至试图使用 Tomcat 或 Undertow。我很感激任何帮助!
采纳答案by Harish Gokavarapu
Spring Boot configuration using properties, allows configuring only one connector. What you need is multiple connectors and for this you have to write a Configuration class. Follow instructions in
Spring Boot 使用属性配置,只允许配置一个连接器。您需要的是多个连接器,为此您必须编写一个 Configuration 类。按照说明操作
You can find a working example of configuring https through properties and then http though EmbeddedServletContainerCustomizer below
您可以在下面找到通过属性配置 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);
}
}
};
}
}
回答by Stan Sokolov
Bellow is a simple example of how to enable both HTTP/HTTPS ports for undertow.
Bellow 是一个如何为 undertow 启用 HTTP/HTTPS 端口的简单示例。
Spring Boot only lets to open one port by configuration. Second port has to be opened programmatically.
Spring Boot 只允许通过配置打开一个端口。第二个端口必须以编程方式打开。
Open HTTP port first programmatically.
首先以编程方式打开 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
HTTPS 通过配置
Spring can open one either HTTP or HTTPS port reading properties from an available property source. If you add appropriate configuration as shown bellow it would be good enough to have HTTPs port open.
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 by manual setup
HTTPS 通过手动设置
You can open another SSL port the same way as you opened HTTP port if you want by doing this
如果您愿意,您可以像打开 HTTP 端口一样打开另一个 SSL 端口
.addHttpsListener(ssl_port, httpInterface, getSSLContext());
This is how you can create SSL context
这是创建 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;
}
}
回答by acohen
Take a look at: https://github.com/creactiviti/spring-boot-starter-acme. It makes it very easy to auto-generate a LetsEncrypt based SSL certificate.
看看:https: //github.com/creactiviti/spring-boot-starter-acme。它使自动生成基于 LetsEncrypt 的 SSL 证书变得非常容易。
From the README:
从自述文件:
Add the module to your pom.xml file as a dependency.
Build your project.
Deploy it to a target machine and point your domain name to the IP address of that machine. LetsEncrypt validates your ownership of the domain by making a callback to the http://your-domain/.well-known/acme-challenge/{token} endpoint exposed by this module.
Make sure that your server has openssl available on its $PATH.
To activate spring-boot-starter-acme and generate a certificate execute:
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
Check your console for a confirmation that the certificate was successfully generated.
Stop your application and configure it to make use of the generated certificate:
server.port=443 server.ssl.key-store=keystore.p12 server.ssl.key-store-password=password server.ssl.keyStoreType=PKCS12
将该模块作为依赖项添加到您的 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
回答by NickDK
The currently accepted answer works perfectly but needs some adaption if you want it to work with Spring Boot 2.0.0 and onwards:
当前接受的答案完美无缺,但如果您希望它与 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;
}
}
or the kotlin version:
或 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
}
}
回答by max
Another Spring boot 2.x solution:
另一个 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;
}
And set in your properties server.port=443
并在您的属性中设置server.port=443
回答by Shai Almog
The top answers are all great and probably work but I've been using Undertow with JHipster so they didn't work for me (and this was the main searchresult). The right code for Undertow is mentioned in this issuespecifically:
最重要的答案都很棒,可能有用,但我一直在使用 Undertow 和 JHipster,所以它们对我不起作用(这是主要的搜索结果)。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;
}