【问题标题】:Spring Security 3.1.0 - Remember-me does not work as expectedSpring Security 3.1.0 - 记住我没有按预期工作
【发布时间】:2012-03-06 21:07:16
【问题描述】:

我在使用 Spring Security 的 3.1.0 记住我的 cookie 时遇到问题。我需要尽快找到解决方案,但我找不到这个问题的原因。

这些是我正在遵循的步骤:

  • 转到我的应用网址(例如http://myapp/app.htm
  • 我被重定向到登录页面,所以我登录了
  • 登录后,关闭浏览器而不退出
  • 打开浏览器并转到我的应用网址

此时我希望绕过登录表单进入我的应用程序,因为记住我的 cookie 仍在我的浏览器中。尽管如此,登录页面再次出现

  • 再次转到我的应用网址

再试一次,我可以绕过登录表单正常进入我的应用程序。

这很令人困惑,到目前为止我找不到解释。

我尝试调试这两种尝试,并在 Spring Security 的 RememberMeAuthenticationFilter 被触发时发现以下内容:

尝试 1
请求路径 = /app.htm: request.getCookies() 不包含我的 SPRING_SECURITY_REMEMBER_ME_COOKIE,因此我被重定向到登录页面 请求路径 = /security/login.htm:此时 request.getCookies() 确实有我的 SPRING_SECURITY_REMEMBER_ME_COOKIE,它被接受了;反正我已经被重定向到登录页面了

尝试 2
记住我的 cookie 已经被接受,所以我可以毫无问题地进入我的应用程序。

以下是 Spring Security XML 配置和两次尝试的日志。

对此的任何帮助将不胜感激!


Spring Security 配置(我将省略有关 daoAuthenticationProvider 和事件侦听器的所有内容):

<sec:http auto-config="false" use-expressions="true" authentication-manager-ref="authenticationManager">
    <sec:custom-filter ref="sessionLocaleResolvingFilter" before="FORM_LOGIN_FILTER"/>

    <sec:intercept-url pattern="/security/*.htm" requires-channel="https" />
    <sec:intercept-url pattern="/retrieve-password/*.htm" requires-channel="https" />
    <sec:intercept-url pattern="/messagebroker/*" access="authenticated" requires-channel="http" />
    <sec:intercept-url pattern="/platform/*.htm"
        access="hasRole('limited') or (authenticated and !hasRole('role1') and !hasRole('role2'))"
        requires-channel="http" />
    <sec:intercept-url pattern="/app.htm" access="authenticated" requires-channel="http" />
    <sec:intercept-url pattern="/**" requires-channel="http" />
    <sec:form-login login-page="/security/login.htm" default-target-url="/app.htm"
        login-processing-url="/security/process-login.htm" authentication-failure-url="/security/login.htm?error=true" />
    <sec:logout logout-url="/security/logout.htm" delete-cookies="JSESSIONID,SPRING_SECURITY_REMEMBER_ME_COOKIE"
        logout-success-url="/security/logout-success.htm" invalidate-session="true"/>
    <sec:anonymous/>
    <sec:remember-me use-secure-cookie="true" key="myAppServices" 
        services-ref="ipTokenBasedRememberMeServicesBean" />
    <sec:session-management session-fixation-protection="none"/>
    <sec:access-denied-handler error-page="/denied-access.htm"/>
</sec:http>

<bean id="sessionLocaleResolvingFilter" class="com.myapp.spring.security.SessionLocaleResolvingFilter" />
<bean class="com.myapp.spring.security.IPTokenBasedRememberMeServices"
    id="ipTokenBasedRememberMeServicesBean">
    <constructor-arg value="myAppServices"/>
    <constructor-arg ref="myAppJdbcDaoImpl"/>
</bean>
<bean id="myAppPasswordEncoder" class="com.myapp.spring.security.MyAppPasswordEncoder" />
<bean id="authenticationManager"
    class="o.s.s.authentication.ProviderManager">
    <property name="providers">
        <list>
            <ref local="daoAuthenticationProvider" />
        </list>
    </property>
</bean>
<!-- Other beans... -->

记录第一次尝试(用 o.s 替换 org.springframework 和用 os.s 替换 org.springframework.security):

o.s.s.web.access.channel.ChannelProcessingFilter:134 - Request: FilterInvocation: URL: /app.htm?lang=en; ConfigAttributes: [REQUIRES_INSECURE_CHANNEL]
o.s.s.web.context.HttpSessionSecurityContextRepository:127 - No HttpSession currently exists
o.s.s.web.context.HttpSessionSecurityContextRepository:85 - No SecurityContext was available from the HttpSession: null. A new one will be created.
o.s.s.web.FilterChainProxy:318 - /app.htm?lang=en at position 9 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
o.s.s.web.authentication.AnonymousAuthenticationFilter:102 - Populated SecurityContextHolder with anonymous token: 'o.s.s.authentication.AnonymousAuthenticationToken@90550640: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: o.s.s.web.authentication.WebAuthenticationDetails@7798: RemoteIpAddress: fe80:0:0:0:ec09:25fb:3df4:323b; SessionId: 057E689401E69589BB7359F3E95B4A18; Granted Authorities: ROLE_ANONYMOUS'
o.s.s.web.FilterChainProxy:318 - /app.htm?lang=en at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
o.s.s.web.FilterChainProxy:318 - /app.htm?lang=en at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
o.s.s.web.util.AntPathRequestMatcher:103 - Checking match of request : '/app.htm'; against '/messagebroker/*'
o.s.s.web.util.AntPathRequestMatcher:103 - Checking match of request : '/app.htm'; against '/app.htm'
o.s.s.web.access.intercept.FilterSecurityInterceptor:193 - Secure object: FilterInvocation: URL: /app.htm?lang=en; Attributes: [authenticated]
o.s.s.web.access.intercept.FilterSecurityInterceptor:298 - Previously Authenticated: o.s.s.authentication.AnonymousAuthenticationToken@90550640: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: o.s.s.web.authentication.WebAuthenticationDetails@7798: RemoteIpAddress: fe80:0:0:0:ec09:25fb:3df4:323b; SessionId: 057E689401E69589BB7359F3E95B4A18; Granted Authorities: ROLE_ANONYMOUS
o.s.s.access.vote.AffirmativeBased:65 - Voter: o.s.s.web.access.expression.WebExpressionVoter@1ce3388, returned: -1
o.s.s.web.access.ExceptionTranslationFilter:165 - Access is denied (user is anonymous); redirecting to authentication entry point
o.s.s.access.AccessDeniedException: Access is denied
    at o.s.s.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83)
    at o.s.s.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:205)
    at o.s.s.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:114)
    at o.s.s.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
    at o.s.s.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
    at o.s.s.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
    at o.s.s.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
    (X more)

o.s.s.web.DefaultRedirectStrategy:36 - Redirecting to 'http://arbad67464/services/security/login.htm'
o.s.s.web.context.HttpSessionSecurityContextRepository:269 - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
o.s.s.web.context.SecurityContextPersistenceFilter:97 - SecurityContextHolder now cleared, as request processing completed

o.s.s.web.access.channel.RetryWithHttpsEntryPoint:55 - Redirecting to: https://arbad67464/services/security/login.htm
o.s.s.web.DefaultRedirectStrategy:36 - Redirecting to 'https://arbad67464/services/security/login.htm'

o.s.s.web.access.channel.ChannelProcessingFilter:134 - Request: FilterInvocation: URL: /security/login.htm; ConfigAttributes: [REQUIRES_SECURE_CHANNEL]
o.s.s.web.FilterChainProxy:318 - /security/login.htm at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
o.s.s.web.context.HttpSessionSecurityContextRepository:139 - HttpSession returned null object for SPRING_SECURITY_CONTEXT
o.s.s.web.context.HttpSessionSecurityContextRepository:85 - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@16de87. A new one will be created.
o.s.s.web.FilterChainProxy:318 - /security/login.htm at position 3 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
o.s.s.web.FilterChainProxy:318 - /security/login.htm at position 4 of 11 in additional filter chain; firing Filter: 'SessionLocaleResolvingFilter'
o.s.s.web.FilterChainProxy:318 - /security/login.htm at position 5 of 11 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
o.s.s.web.FilterChainProxy:318 - /security/login.htm at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'

o.s.s.web.FilterChainProxy:318 - /security/login.htm at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
o.s.s.web.FilterChainProxy:318 - /security/login.htm at position 8 of 11 in additional filter chain; firing Filter: 'RememberMeAuthenticationFilter'
com.myapp.spring.security.IPTokenBasedRememberMeServices:103 - Remember-me cookie detected
com.myapp.spring.security.IPTokenBasedRememberMeServices:118 - Remember-me cookie accepted
o.s.s.authentication.ProviderManager:152 - Authentication attempt using o.s.s.authentication.RememberMeAuthenticationProvider

我第二次尝试的日志:

o.s.s.web.access.channel.ChannelProcessingFilter:134 - Request: FilterInvocation: URL: /app.htm?lang=en; ConfigAttributes: [REQUIRES_INSECURE_CHANNEL]
o.s.s.web.context.HttpSessionSecurityContextRepository:158 - Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'o.s.s.core.context.SecurityContextImpl@7db9504: Authentication: o.s.s.authentication.RememberMeAuthenticationToken@7db9504: Principal: com.myapp.spring.security.MyAppUserImpl@9716c62c: Username: somebody@mail.com; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: limited,premium,special; Credentials: [PROTECTED]; Authenticated: true; Details: o.s.s.web.authentication.WebAuthenticationDetails@7798: RemoteIpAddress: fe80:0:0:0:ec09:25fb:3df4:323b; SessionId: 057E689401E69589BB7359F3E95B4A18; Granted Authorities: limited, premium, special'
o.s.s.web.FilterChainProxy:318 - /app.htm?lang=en at position 8 of 11 in additional filter chain; firing Filter: 'RememberMeAuthenticationFilter'
o.s.s.web.authentication.rememberme.RememberMeAuthenticationFilter:142 - SecurityContextHolder not populated with remember-me token, as it already contained: 'o.s.s.authentication.RememberMeAuthenticationToken@7db9504: Principal: com.myapp.spring.security.MyAppUserImpl@9716c62c: Username: somebody@mail.com; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: limited,premium,special; Credentials: [PROTECTED]; Authenticated: true; Details: o.s.s.web.authentication.WebAuthenticationDetails@7798: RemoteIpAddress: fe80:0:0:0:ec09:25fb:3df4:323b; SessionId: 057E689401E69589BB7359F3E95B4A18; Granted Authorities: limited, premium, special'
o.s.s.web.FilterChainProxy:318 - /app.htm?lang=en at position 9 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
o.s.s.web.authentication.AnonymousAuthenticationFilter:107 - SecurityContextHolder not populated with anonymous token, as it already contained: 'o.s.s.authentication.RememberMeAuthenticationToken@7db9504: Principal: com.myapp.spring.security.MyAppUserImpl@9716c62c: Username: somebody@mail.com; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: limited,premium,special; Credentials: [PROTECTED]; Authenticated: true; Details: o.s.s.web.authentication.WebAuthenticationDetails@7798: RemoteIpAddress: fe80:0:0:0:ec09:25fb:3df4:323b; SessionId: 057E689401E69589BB7359F3E95B4A18; Granted Authorities: limited, premium, special'
o.s.s.web.access.intercept.FilterSecurityInterceptor:193 - Secure object: FilterInvocation: URL: /app.htm?lang=en; Attributes: [authenticated]
o.s.s.web.access.intercept.FilterSecurityInterceptor:298 - Previously Authenticated: o.s.s.authentication.RememberMeAuthenticationToken@7db9504: Principal: com.myapp.spring.security.MyAppUserImpl@9716c62c: Username: somebody@mail.com; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: limited,premium,special; Credentials: [PROTECTED]; Authenticated: true; Details: o.s.s.web.authentication.WebAuthenticationDetails@7798: RemoteIpAddress: fe80:0:0:0:ec09:25fb:3df4:323b; SessionId: 057E689401E69589BB7359F3E95B4A18; Granted Authorities: limited, premium, special
o.s.s.access.vote.AffirmativeBased:65 - Voter: o.s.s.web.access.expression.WebExpressionVoter@1ce3388, returned: 1
o.s.s.web.access.intercept.FilterSecurityInterceptor:214 - Authorization successful

【问题讨论】:

  • 请将其精简为更易于消化的内容。现在,它只是一堵文字/代码墙,让人们很容易不花时间看它。此外,仅转储您的所有代码和日志表明您在尝试找出您遇到的实际问题并在此处寻求那个方面的帮助时只需付出很少的努力。
  • 好的,我知道这可能有点压倒性,所以我会尽量减少它。但请理解,当我转储日志时,我只是想提供可能对任何希望提供帮助的人有用的附加信息。它本身并不是最小努力的指标 - 我仔细阅读了日志并调试了我的应用程序,并在发布之前尝试在多个地方找到解决方案。此外,我没有转储所有代码,只转储 XML。如果我没有,怎么会有人帮忙?无论如何,感谢您的评论。

标签: spring-security remember-me


【解决方案1】:

我猜这与您将某些 URL 配置为使用 HTTPS 的事实有关。

remember-me cookie 将被标记为安全(您应该能够在浏览器接收到的 set-cookie 标头中看到这一点,也可能在浏览器 cookie 缓存中看到)。由于对/app 的请求是通过HTTP 进行的,因此不会发送cookie。但是,登录页面的请求被重定向到 HTTPS,此时将发送 cookie

您应该始终使用 HTTPS。配置起来更简单,否则您的应用程序并不真正安全。但是,remember-me namespace element 中还有一个 use-secure-cookie 选项,您可以将其设置为 false 以覆盖默认行为。

【讨论】:

  • 是的,这就是问题所在。我尝试从我的&lt;intercept-url&gt; 元素中删除所有requires-channel 属性,以便在任何情况下都不强制使用HTTPS,并且在第一次尝试中检测到了remember-me cookie。尽管事实上它并不完全安全,但我被要求按照我在 XML 中的方式配置 HTTPS,但也许我需要在整个会话中使用它,以便这些 cookie 正常工作。我会尝试调整频道配置。完成后,我将发布结果。非常感谢卢克!
  • 酷。请注意,正如我所说,您还可以强制将 cookie 标记为不安全,以便在您真正想要的情况下通过 HTTP 和 HTTPS 发送它。
【解决方案2】:

在 Spring 安全性中,它们提供了两种使用 rememberMe 服务的方法。

  1. 在rememberMeService定义中,设置一个属性alwaysRememberMe为true。 在这种情况下,每当用户第一次尝试访问登录所需的安全 URL 页。一旦用户使用正确的用户名和密码登录,之后就不会 要求您登录,直到您注销。

  2. 在登录页面中添加一个名为“_spring_security_remember_me”的记住我复选框 和价值=“真”。 在这种情况下,当用户选择记住我复选框时,只有它能够访问 在您注销之前没有登录页面的安全 URL。

它对我有用..

【讨论】:

    猜你喜欢
    • 2018-12-12
    • 1970-01-01
    • 1970-01-01
    • 2020-01-18
    • 2011-03-09
    • 2015-05-10
    • 2012-04-20
    • 2018-09-23
    • 2016-10-25
    相关资源
    最近更新 更多