我是Spring框架的新手,我搜索了与此主题相关的每个可能的SO链接,但可以找到任何正确的解决方案。 我有一个在JBoss Wildfly上运行的应用程序。它位于AWS EC2实例上,该实例位于Elastic Load Balancer(ELB)后面。 ELB中配置了SSL,因此它只接受来自客户端的HTTPS请求,但我的应用服务器只通过HTTP与ELB通信。我的应用程序使用Spring MVC和Spring Security进行前端/安全管理。 我的security-context.xml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<context:property-placeholder location="/WEB-INF/config.properties" />
<context:annotation-config></context:annotation-config>
<context:component-scan base-package="com.etech.security"> </context:component-scan>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="xxx@xxxx.com"
authorities="admin" password="xxxxxxxx" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
<security:http use-expressions="true">
<security:intercept-url pattern="/" access="isAuthenticated()" />
<security:intercept-url pattern="/dashboard"
access="isAuthenticated()" />
<security:intercept-url pattern="/resources/**" access="permitAll" />
<security:intercept-url pattern="/login" access="permitAll" />
<security:intercept-url pattern="/**" access="denyAll" />
<security:form-login login-page="/login"
authentication-success-handler-ref="asyncAuthenticationSuccessHandler"
authentication-failure-handler-ref="asyncAuthenticationFailureHandler" />
<security:logout logout-url="/logout" logout-success-url="/" />
</security:http>
<bean id="asyncAuthenticationSuccessHandler"
class="com.etech.security.AsyncAuthenticationSuccessHandler">
<constructor-arg ref="supportMailPassword"></constructor-arg>
</bean>
此设置的问题是,一旦通过身份验证,应用程序就会返回到客户端的HTTP链接,客户端无法访问该链接,因为ELB仅允许HTTPS URL。如下所示:
客户--HTTPS ---&gt; ELB --- HTTP - &gt;应用服务器/应用
客户端&lt; - HTTP-- ELB&lt; --- HTTP --- AppServer / Application
但实际上应该这样做,
客户--HTTPS ---&gt; ELB --- HTTP - &gt;应用服务器/应用
客户端&lt; - HTTPS-- ELB&lt; --- HTTPS --- AppServer / Application
对此有什么正确的方法,我是否需要使用在身份验证/处理后绑定到Response的任何类型的Filter,我可以将响应URL更改为HTTPS?
答案 0 :(得分:1)
在深入研究问题之后,我发现这主要是由于Spring Dispatcher Servlet将入站连接检测为不安全,即所有连接都是通过HTTP进行的,这将导致所有出站连接都通过HTTP进行。
Spring会通过以下方法调用检测到这一点:HttpServletRequest.isSecure(),这将始终返回false,因为从ELB到Application Server的连接是通过HTTP而不是HTTPS。
有一个很好的blog post描述了这个完全相同的问题,并发布了一个我自己使用的简单解决方案。
解决方案是使用放置在过滤器链顶部的过滤器。它会拦截所有传入的请求,用自定义的HttpServletRequest替换入站的HttpServletRequest,这将使isSecure()方法返回true。然后Spring调度程序Servlet会检测到这一点并将HTTPS响应发送回客户端。
步骤很简单:
创建自定义HttpServletRequestWrapper
public class CustomWrapper extends HttpServletRequestWrapper
{
public CustomWrapper(HttpServletRequest request) {
super(request);
}
public boolean isSecure()
{
return true;
}
public String getScheme()
{
return "https";
}
}
创建一个可以使用此包装器的过滤器
public class CustomFilter implements Filter
{
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException
{
CustomWrapper wrapper = new CustomWrapper((HttpServletRequest) request);
chain.doFilter(wrapper, response);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
在web.xml中,在任何其他过滤器之前添加此过滤器,包括Spring Security Filter chain。