英文:
How to enable only http on some endpoints and https on some other endpoints in a spring boot rest controller?
问题
我想在一些端点上启用 http,并在另一组端点上启用 https。
我得到了一些解决方案,比如通过 application.properties
配置 https,并通过以编程方式创建额外连接器来配置 http,但所有的结果都会对所有端点同时启用 http 和 https。
有人可以告诉我如何配置一些端点为 https,另一些端点为 http 吗?
英文:
I want to enable http on some endpoints and https on another set of endpoints.
I got solutions like configure https through application.properties
and http by programmatically creating an extra connector, but all the results enable both http and https for all endpoints.
Can someone let me know how to configure some endpoints with https and some end points with http?
答案1
得分: 1
我已经为我使用的**Jetty** servlet解决了这个问题。如果你使用默认的TomCat servlet,你可能需要进行类似的操作来适用于TomCat。
首先,我将ssl端口设置为默认激活状态。为了允许http访问,您需要在配置中配置一个额外的http端口。然后,您需要添加一个服务器处理程序(Handler)。您可以添加"SecuredRedirectHandler"处理程序,将所有http请求重定向到https端口。由于我们不想重定向所有http请求,我们创建了一个自定义的"CustomRedirectHandler",它继承自"SecuredRedirectHandler"。
```java
@Bean
public ConfigurableServletWebServerFactory webServerFactory() {
JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
factory.addServerCustomizers(new JettyServerCustomizer() {
@Override
public void customize(Server server) {
final HttpConnectionFactory httpConnectionFactory = server.getConnectors()[0].getConnectionFactory(HttpConnectionFactory.class);
// 启用指定端口的HTTP
final ServerConnector httpConnector = new ServerConnector(server, httpConnectionFactory);
httpConnector.setPort(serverProperties.intHttpPort() /* HTTP */);
server.addConnector(httpConnector);
// 将CustomRedirectHandler添加到服务器处理程序
final HandlerList handlerList = new HandlerList();
handlerList.addHandler(new CustomRedirectHandler());
for(Handler handler : server.getHandlers()) {
handlerList.addHandler(handler);
}
server.setHandler(handlerList);
}
});
return factory;
}
在我们的"CustomRedirectHandler"中,我们可以检查请求的端点是否在我们的"allowed http"数组中。如果它已经请求了https,或者允许使用http,则不做任何操作,否则重定向到https。我的示例只允许针对以"/.well-known/acme-challenge/"开头的端点使用http,以允许对http://example.com/.well-known/acme-challenge/TOKEN的请求,例如。
public class CustomRedirectHandler extends SecuredRedirectHandler {
private final String[] allowedHttp = {"/.well-known/acme-challenge/"};
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
HttpChannel channel = baseRequest.getHttpChannel();
if (baseRequest.isSecure() || channel == null) {
// 已经请求了https,无需处理
return;
}
// 检查请求是否允许使用http
if (allowHttp(baseRequest)) {
return;
}
// 否则重定向到https
super.handle(target, baseRequest, request, response);
}
public boolean allowHttp(Request baseRequest) {
String pathInfo = baseRequest.getPathInfo();
if (pathInfo == null) {
return false;
}
for (String allowed : allowedHttp) {
if (pathInfo.startsWith(allowed)) {
return true;
}
}
return false;
}
}
<details>
<summary>英文:</summary>
I figured this out for **Jetty** servlet which I use. If you use the default TomCat servlet you will have to do something similar that works for TomCat I suppose.
So to start with I have a ssl port as default that is activated. To also allow http you need to configure an additional http port in your config. Then you need to add a server Handler. You could add the Handler SecuredRedirectHandler to redirect ALL http requests to the https port. Since we don't want to redirect ALL http requests we make our own CustomRedirectHandler that extends SecuredRedirectHandler.
@Bean
public ConfigurableServletWebServerFactory webServerFactory() {
JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
factory.addServerCustomizers(new JettyServerCustomizer() {
@Override
public void customize(Server server) {
final HttpConnectionFactory httpConnectionFactory = server.getConnectors()[0].getConnectionFactory(HttpConnectionFactory.class);
// Enable HTTP for assigned port
final ServerConnector httpConnector = new ServerConnector(server, httpConnectionFactory);
httpConnector.setPort(serverProperties.intHttpPort() /* HTTP */);
server.addConnector(httpConnector);
// Add a CustomRedirectHandler to Server Handlers
final HandlerList handlerList = new HandlerList();
handlerList.addHandler(new CustomRedirectHandler());
for(Handler handler : server.getHandlers()) {
handlerList.addHandler(handler);
}
server.setHandler(handlerList);
}
});
return factory;
}
In our CustomRedirectHandler we can check if the requested endpoint is in our "allowed http" array. If it already request https or is allowed http then we do nothing, else redirect to https. My example allows http only for the endpoint that starts with "/.well-known/acme-challenge/" to allow requests to http://example.com/.well-known/acme-challenge/TOKEN for example.
public class CustomRedirectHandler extends SecuredRedirectHandler {
private final String[] allowedHttp = {"/.well-known/acme-challenge/"};
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
HttpChannel channel = baseRequest.getHttpChannel();
if (baseRequest.isSecure() || channel == null) {
// nothing to do, already requested https
return;
}
// Check if request is for allowed http
if (allowHttp(baseRequest)) {
return;
}
// Else Redirect to https
super.handle(target, baseRequest, request, response);
}
public boolean allowHttp(Request baseRequest) {
String pathInfo = baseRequest.getPathInfo();
if (pathInfo == null) {
return false;
}
for (String allowed : allowedHttp) {
if (pathInfo.startsWith(allowed)) {
return true;
}
}
return false;
}
}
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论