Spring Security 3.1.0 - 无法从HTTPS切换到HTTP

时间:2012-01-25 15:04:44

标签: java https spring-security

我是Spring Security的新手,所以我制作了一个小型的webapp,以便尝试并找到一个对我正在处理的项目有用的配置。 我强迫我的登录页面通过HTTPS访问,我需要在登录后切换回HTTP。换句话说:

  • 登录页面:仅限HTTPS
  • 其他页面:仅限HTTP

我尝试了几种方法但是我不能像上面所说的那样使它工作。 我读了Spring Security FAQ,我发现没有“自然”的方式做我想做的事,但我被要求这样做,因此我需要一个我自己找不到的解决方法。

我正在使用Spring Security 3.1.0。 我的Web容器是Tomcat 6.0.33。

这是我的Spring Security配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:sec="http://www.springframework.org/schema/security"
    xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <sec:http auto-config="true" use-expressions="true">

        <sec:intercept-url pattern="/log*.htm" access="anonymous"
            requires-channel="https" />
        <sec:intercept-url pattern="/admin/**" access="hasRole('admin')"
            requires-channel="http" />
        <sec:intercept-url pattern="/**"
            requires-channel="http" access="hasRole('authenticated')" />

        <sec:form-login login-page="/login.htm"
            default-target-url="/index.htm" authentication-failure-url="/login.htm?error=true"
            always-use-default-target="true" />
        <sec:logout logout-url="/logout.htm" delete-cookies="JSESSIONID" invalidate-session="true" />
        <sec:anonymous/>
        <sec:remember-me use-secure-cookie="true" />
    </sec:http>

    <sec:authentication-manager>
        <sec:authentication-provider>
            <sec:user-service>
                <sec:user name="johnny" password="johnny" authorities="authenticated, admin" />
                <sec:user name="charlie" password="charlie"
                    authorities="authenticated" />
            </sec:user-service>
        </sec:authentication-provider>
    </sec:authentication-manager>

</beans>

任何帮助将不胜感激。 提前谢谢!

2 个答案:

答案 0 :(得分:1)

我发现此问题的解决方法是禁用Spring Security的默认会话固定保护。我必须在我首次描述的XML配置中添加“session-management”元素。

<sec:http auto-config="true">

    <!-- ... -->

    <sec:session-management session-fixation-protection="none"/>

    <!-- ... -->
</sec:http>

除此之外,我们必须提供的“应用程序URL”的URL不是登录URL,而是主页URL,例如不是http://myapp/login.htm但是http://myapp/index.htm。这样做,如果用户已登录或具有记住我的cookie,他们将能够毫无问题地进入并且浏览器继续使用HTTP协议。如果没有,则使用HTTPS将用户重定向到登录页面,并在成功登录后,浏览器正确切换回HTTP。请考虑到这一点,因为如果您直接写入(或单击)登录URL,将始终保持HTTPS。

答案 1 :(得分:0)

可以通过在过滤器链中添加一个更改cookie的过滤器

在配置文件中创建过滤器并将其添加到过滤器链中,如下所示:

<bean name="httpsCookieFilter" class="bla.bla.bla.HttpsCookieFilter"/>

<security:http auto-config="false" entry-point-ref="authenticationEntryPoint">
...
    <security:custom-filter position="FIRST" ref="httpsCookieFilter" />
...
</security:http>

您的过滤器代码看起来像这样

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * Sessions created under HTTPS, for which the session cookie is marked as “secure”, cannot subsequently be used under 
 * HTTP. The browser will not send the cookie back to the server and any session state will be lost (including the
 * security context information)
 *
 * Tomcat tracks user sessions with the help of the JSESSIONID cookie. If you enter into HTTPS with Tomcat, the cookie
 * will come back with the secure property being set to true. Subsequently when the redirection to http occurs, the
 * browser will not transmit the JSESSIONID cookie and you'll get a new session.
 *
 * This filter overrides the default Tomcat JSESSIONID behaviour
 */
public class HttpsCookieFilter implements Filter {

    @Override
    public void init(FilterConfig arg0) throws ServletException {
    }

    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        final HttpServletRequest httpRequest = (HttpServletRequest) request;
        final HttpServletResponse httpResponse = (HttpServletResponse) response;
        final HttpSession session = httpRequest.getSession(false);

        if (session != null) {
            final Cookie sessionCookie = new Cookie("JSESSIONID", session.getId());
            sessionCookie.setMaxAge(-1);
            sessionCookie.setSecure(false);
            sessionCookie.setPath(httpRequest.getContextPath());
            httpResponse.addCookie(sessionCookie);
        }

        chain.doFilter(request, response);
    }

}