【问题标题】:Spring security 'remember me' cookie not avaiable in first requestSpring security 'remember me' cookie 在第一个请求中不可用
【发布时间】:2013-12-23 16:06:17
【问题描述】:

在登录请求后,我无法检索 Spring 记住我的 cookie,但它在对受保护页面的下一个请求中可以正常工作。谁能告诉我怎样才能马上拿到它?

我在登录请求中设置了记住我的 cookie,但在 Spring 重定向回原始(受保护的)url 后无法检索它。

一步一步:

  1. 浏览器转到 example.com/protected
  2. Spring 重定向到登录表单页面
  3. 成功登录后,SPRING_SECURITY_REMEMBER_ME_COOKIE 设置在 org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices 的一个非常薄的自定义子类中
  4. 看起来 Spring 重定向回 example.com/protected,没有往返浏览器,登录“servlet”和受保护页面都由 Tomcat 6 中的同一线程处理。
  5. org.springframework.security.web.access.expression.WebSecurityExpressionRoot 的子类具有从
  6. 调用的方法
  7. 在我们的 method() 中,request.getCookies() 不会在第一次请求时提供记住我的 cookie,而是在之后的所有请求中提供。
  8. 我们的应用程序出现了一些问题,因为 cookie 丢失了......

到目前为止,我的理论是我没有正确理解 SavedRequest。

这里是精简配置:

<http auto-config="false" use-expressions="true" authentication-manager-ref="myAuthenticationManager" path-type="regex">
    <form-login authentication-success-handler-ref="myAuthenticationSuccessHandler" login-page="..." login-processing-url="..." authentication-failure-url="..." username-parameter="username" password-parameter="password" />

    <custom-filter ref="logoutFilter" position="LOGOUT_FILTER"/>
    <expression-handler ref="myWebSecurityExpressionHandler" />

    <custom-filter ref="myCustomeFilter1" before="FORM_LOGIN_FILTER"/>
    <custom-filter ref="myCustomeFilter2" position="BASIC_AUTH_FILTER"/>
    <custom-filter ref="mySecurityClientTokenAuthenticationFilter" after="LOGOUT_FILTER" />

    <access-denied-handler ref="myAccessDeniedHandler"/>
    <intercept-url pattern="xxx"
                   access="method()"/>

    <intercept-url pattern="yyy"
                   access="method()"/>
    <remember-me services-ref="rememberMeServices"  key="my_remember"/>
</http>

我尝试添加以下内容,唯一的结果是用户没有被重定向到原始页面。

<http ...
    <request-cache ref="nullRequestCache"/>
</http>
<bean:bean id="nullRequestCache" class="org.springframework.security.web.savedrequest.NullRequestCache"/>

【问题讨论】:

  • 你找到解决这个问题的方法了吗?
  • 遇到同样的问题 - 使用/访问原始请求不是一个选项 - 因为它影响了第 3 方库......似乎是 Spring 安全性中的一个错误,而不是错误的访问方式?
  • 我不确定请求缓存是否与您的问题有关,但是如果您想使用 NullRequestCache 并且仍然重定向,则需要在 SavedRequestAwareAuthenticationSuccessHandler 上配置重定向参数(或提供您自己的处理程序)并将其添加到您的所有登录链接。您还必须扩展 LoginUrlAuthenticationEntryPoint 并覆盖 determineUrlToUseForThisRequest 以在 spring security 启动重定向时添加参数(当您在登录前访问安全页面时)。

标签: java spring cookies spring-security


【解决方案1】:

RememberMeService的autoLogin()方法中使用request.getCookie()时,传入的请求是SavedRequestAwareWrapper,它封装了原始请求和保存的请求,重写了getCookies方法。

@Override
public Cookie[] getCookies() {
    List<Cookie> cookies = savedRequest.getCookies();
    return cookies.toArray(new Cookie[cookies.size()]);
}

因此,当你想从 request 中获取 cookie 时,实际上是从 savedRequest 中获取 cookie。但是,cookie可能存在于原始请求中。

您可能应该获得获取所需 cookie 的原始请求。例如:

public class ApplicationRememberMeServiceImpl implements RememberMeService, LogoutHandler {

    public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response) {

        HttpServletRequestWrapper savedRequestWrapper = (HttpServletRequestWrapper) ((HttpServletRequestWrapper) request).getRequest();
        HttpServletRequest httpServletRequest = (HttpServletRequest) savedRequestWrapper.getRequest();

        Cookie cookie = WebUtils.getCookie(httpServletRequest, cookieName);
        // logic continues...

    }

}

2015 年 3 月 5 日更新

由于spring security会对原始HttpServletRequest进行多次包装,所以采用下面的方式提取原始请求更安全:

public class ApplicationRememberMeServiceImpl implements RememberMeService, LogoutHandler {

    public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response) {

        HttpServletRequest httpServletRequest = request;

        // Get the original request from multiple wrapped HttpServletRequest
        if(httpServletRequest instanceof HttpServletRequestWrapper) {

            HttpServletRequestWrapper httpServletRequestWrapper = (HttpServletRequestWrapper) httpServletRequest;
            while(httpServletRequestWrapper.getRequest() instanceof HttpServletRequestWrapper) {
                httpServletRequestWrapper = (HttpServletRequestWrapper) httpServletRequestWrapper.getRequest();
            }

            httpServletRequest = (HttpServletRequest) httpServletRequestWrapper.getRequest();

        }

        Cookie cookie = WebUtils.getCookie(httpServletRequest, cookieName);
        // logic continues...

    }

}

【讨论】:

    猜你喜欢
    • 2012-04-21
    • 1970-01-01
    • 2010-11-04
    • 2019-06-10
    • 1970-01-01
    • 2011-04-14
    • 2021-02-04
    • 2012-04-29
    • 2017-06-02
    相关资源
    最近更新 更多