我正在尝试使用以下命令在我的Spring Boot应用程序中将http重定向到https:
http.requiresChannel().anyRequest().requiresSecure();
但是我越来越ERR_TOO_MANY_REDIRECTS。原因是负载均衡器将所有https都转换为http并将http定向到端口8082,因此该应用似乎从未看到过https。
ERR_TOO_MANY_REDIRECTS
我尝试通过在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。我不明白我在做什么错?我的第一个想法是:
example.com/login
https://example.com/login
我可以在WebSecurityConfiguration中注入IsSecureFilter来检索isSecure吗?
我是否以正确的方式将IsSecureFilter筛选器添加到配置中。
包装过滤器关系是否正确定义?
编辑
1) 我更改http.addFilterAfter(new isSecureFilter(), ChannelProcessingFilter.class);为http.addFilterAfter(isSecureFilter, ChannelProcessingFilter.class);,仍然没有效果。
http.addFilterAfter(new isSecureFilter(), ChannelProcessingFilter.class);
http.addFilterAfter(isSecureFilter, ChannelProcessingFilter.class);
2) 我尝试更改http.addFilterBefore(isSecureFilter, ChannelProcessingFilter.class);为,http.addFilterAfter(isSecureFilter, ChannelProcessingFilter.class);但仍然没有任何更改。
http.addFilterBefore(isSecureFilter, ChannelProcessingFilter.class);
这是解决此问题的解决方案。根据调查,由于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()。