我正在尝试使用以下方法在我的Spring Boot应用程序中将http重定向到https:
http.requiresChannel().anyRequest().requiresSecure();
但是我得到ERR_TOO_MANY_REDIRECTS
。原因是负载均衡器将所有https都转换为http并将http定向到端口8082,因此该应用似乎从未看到过https。
我试图通过在http到https重定向之前添加isSecure来解决此问题,例如在我的配置中:
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
//variables
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/css/**", "/js/**", "/admin/**")
.permitAll().anyRequest().authenticated().and()
.addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class)
.formLogin().loginPage("/login").permitAll().and()
.logout().logoutSuccessUrl("/");
//hsts
http.headers().httpStrictTransportSecurity()
.includeSubDomains(true).maxAgeInSeconds(31536000);
http.addFilterBefore(new IsSecureFilter(), ChannelProcessingFilter.class);
//https compulsion
if(!isSecureFilter.isSecure()) {
http.requiresChannel().anyRequest().requiresSecure();
}
}
//rest of the code
}
我正在尝试使用HttpServletRequestWrapper,以便可以通过下面创建的IsSecureFilter在上面的WebSecurityConfiguration中重复使用isSecure,以防止无限重定向:
public class RequestWrapper extends HttpServletRequestWrapper {
private boolean isSecure;
public RequestWrapper(HttpServletRequest request) throws IOException
{
//So that other request method behave just like before
super(request);
this.isSecure = request.isSecure();
}
//Use this method to read the request isSecure N times
public boolean isSecure() {
return this.isSecure;
}
}
下面是我尝试在WebSecurityConfiguration中注入的过滤器,以使用上面的isSecure值:
@Component
public class IsSecureFilter extends GenericFilterBean {
private boolean isSecure;
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = new RequestWrapper((HttpServletRequest) request);
this.isSecure = req.isSecure();
chain.doFilter(req, response);
}
public boolean isSecure() {
return this.isSecure;
}
}
因此,运行上面的代码并将example.com/login
放在浏览器中确实会重定向到https://example.com/login
,但是我仍然得到ERR_TOO_MANY_REDIRECTS
。
我不明白我在做什么错?
我的第一个想法是:
我可以在WebSecurityConfiguration中注入IsSecureFilter来检索isSecure吗?
我以正确的方式向配置中添加了IsSecureFilter过滤器。
包装过滤器关系是否正确定义?
编辑
1)我将http.addFilterAfter(new isSecureFilter(), ChannelProcessingFilter.class);
更改为http.addFilterAfter(isSecureFilter, ChannelProcessingFilter.class);
,仍然没有效果。
2)我尝试将http.addFilterBefore(isSecureFilter, ChannelProcessingFilter.class);
更改为http.addFilterAfter(isSecureFilter, ChannelProcessingFilter.class);
,但这仍然没有任何改变。
答案 0 :(得分:2)
这是解决此问题的解决方案。根据调查,由于8080和8082用于识别HTTP通信和HTTPS通信,因此添加了一些代码来检查端口号,而不是“ isSecure”,以确定是否重定向HTTP请求。代码如下:
public class IsSecureFilter extends GenericFilterBean {
private boolean isSecure;
private int port;
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = new RequestWrapper((HttpServletRequest) request);
HttpServletResponse res = (HttpServletResponse) response;
this.isSecure = req.isSecure();
this.port = req.getLocalPort();
System.out.println("[DEBUG] : isSecure FILTER :: " + isSecure);
System.out.println("[DEBUG] : port FILTER :: " + port);
System.out.println("[DEBUG] : URL :: " + req.getRequestURL());
String url = req.getRequestURL().toString().toLowerCase();
if(url.endsWith("/login") && url.startsWith("http:") && port == 8080){
url = url.replace("http:", "https:");
String queries = req.getQueryString();
if (queries == null) {
queries = "";
} else {
queries = "?" + queries;
}
url += queries;
res.sendRedirect(url);
}
else {
chain.doFilter(req, response);
}
}
public boolean isSecure() {
return this.isSecure;
}
public boolean setIsSecure(boolean isSecure) {
return this.isSecure = isSecure;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
}
并删除WebSecurityConfiguration类中的http.requiresChannel()。anyRequest()。requiresSecure()。