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

发布于 2024-12-29 04:49:12 字数 2379 浏览 0 评论 0原文

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

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

我尝试了多种方法,但无法使其正常工作上面说了。 我阅读了 Spring Security 常见问题解答 并我发现没有“自然”的方式来做我想做的事,但我被要求这样做,因此我需要一个我自己找不到的解决方法。

我正在使用 Spring Security 3.1.0。 我的网络容器是 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>

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

I am new to Spring Security, so I made a small webapp in order to try it and find a configuration that will be useful for the project I am working on.
I am forcing my login page to be accessed via HTTPS, and I need to switch back to HTTP after logging in. In other words:

  • Login page: HTTPS only
  • Other pages: HTTP only

I tried several ways but I cannot make it work as I said above.
I read the Spring Security FAQ and I see that there is no "natural" way of doing what I want, but I have been asked to do so, hence I need a workaround which I cannot find by myself.

I am using Spring Security 3.1.0.
My web container is Tomcat 6.0.33.

This is my Spring Security configuration:

<?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>

Any help will be appreciated.
Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

故事与诗 2025-01-05 04:49:12

我发现这个问题的解决方法是禁用 Spring Security 的默认会话固定保护。我必须将“会话管理”元素添加到我首先描述的 XML 配置中。

<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 将始终保持。

The workaround I found for this problem is disabling Spring Security's default session fixation protection. I had to add a "session-management" element to the XML configuration I first described.

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

    <!-- ... -->

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

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

In addition to this, the URL we have to provide as the "application URL" is not the login URL but the Home Page URL, e.g. NOT http://myapp/login.htm BUT http://myapp/index.htm. Doing so, if the user is logged in or has a remember-me cookie, they will be able to enter without problem and the browser keeps using HTTP protocol. If not, the user is redirected to the login page using HTTPS, and after a successful login the browser switches back to HTTP correctly. Please take this into account, because if you write (or click) the login URL directly, HTTPS will be maintained all the time.

毅然前行 2025-01-05 04:49:12

可以通过在过滤器链中添加一个过滤器来更改您的 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);
    }

}

It is possible by adding a filter into the filter chain that changes your cookie

In your config file create the filter and add it into the filter chain as follows:

<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>

And your Filter code looks something like this

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);
    }

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文