对于最新的稳定版本,请使用 Spring Security 6.4.3spring-doc.cadn.net.cn

Remember-Me 身份验证

概述

Remember-me 或 persistent-login 身份验证是指 Web 站点能够在会话之间记住主体的身份。 这通常是通过向浏览器发送 cookie 来实现的,该 cookie 在将来的会话中被检测到并导致自动登录。 Spring Security 为这些作的发生提供了必要的钩子,并且有两个具体的记住我实现。 一种使用哈希来保持基于 Cookie 的令牌的安全性,另一种使用数据库或其他持久性存储机制来存储生成的令牌。spring-doc.cadn.net.cn

请注意,这两种实现都需要UserDetailsService. 如果您使用的身份验证提供程序不使用UserDetailsService(例如,LDAP 提供程序),那么除非您还有一个UserDetailsServicebean 中的应用程序上下文中。spring-doc.cadn.net.cn

简单的基于哈希的代币方法

这种方法使用哈希来实现有用的 remember-me 策略。 实质上,在成功进行交互式身份验证后,会将 Cookie 发送到浏览器,其组成如下:spring-doc.cadn.net.cn

base64(username + ":" + expirationTime + ":" +
md5Hex(username + ":" + expirationTime + ":" password + ":" + key))

username:          As identifiable to the UserDetailsService
password:          That matches the one in the retrieved UserDetails
expirationTime:    The date and time when the remember-me token expires, expressed in milliseconds
key:               A private key to prevent modification of the remember-me token

因此,记住我令牌仅在指定的时间段内有效,并且用户名、密码和密钥不会更改。 值得注意的是,这存在潜在的安全问题,因为捕获的 remember-me 令牌将可以从任何用户代理使用,直到令牌过期。 这与摘要式身份验证的问题相同。 如果委托人知道已捕获令牌,他们可以轻松更改密码并立即使所有已颁发的 remember-me 令牌失效。 如果需要更高的安全性,则应使用下一节中描述的方法。 或者,根本不应该使用 remember-me 服务。spring-doc.cadn.net.cn

如果您熟悉命名空间配置一章中讨论的主题,则只需添加<remember-me>元素:spring-doc.cadn.net.cn

<http>
...
<remember-me key="myAppKey"/>
</http>

UserDetailsService通常会自动选择。 如果应用程序上下文中有多个 Cookie,则需要指定应将哪个 API 与user-service-ref属性,其中值是UserDetailsService豆。spring-doc.cadn.net.cn

持久令牌方法

此方法基于文章 http://jaspan.com/improved_persistent_login_cookie_best_practice 进行了一些细微的修改[1]. 要将此方法与命名空间配置一起使用,您需要提供数据源引用:spring-doc.cadn.net.cn

<http>
...
<remember-me data-source-ref="someDataSource"/>
</http>

数据库应包含一个persistent_loginstable 中,使用以下 SQL(或等效 SQL)创建:spring-doc.cadn.net.cn

create table persistent_logins (username varchar(64) not null,
								series varchar(64) primary key,
								token varchar(64) not null,
								last_used timestamp not null)

Remember-Me 接口和实现

Remember-me 用于UsernamePasswordAuthenticationFilter实现的 API 中,并通过AbstractAuthenticationProcessingFilter超类。 它也用于BasicAuthenticationFilter. 钩子将调用一个具体的RememberMeServices在适当的时间。 界面如下所示:spring-doc.cadn.net.cn

Authentication autoLogin(HttpServletRequest request, HttpServletResponse response);

void loginFail(HttpServletRequest request, HttpServletResponse response);

void loginSuccess(HttpServletRequest request, HttpServletResponse response,
	Authentication successfulAuthentication);

请参阅 Javadoc 以更全面地讨论这些方法的作用,但请注意,在此阶段AbstractAuthenticationProcessingFilter仅调用loginFail()loginSuccess()方法。 这autoLogin()method 由RememberMeAuthenticationFilter每当SecurityContextHolder不包含Authentication. 因此,此接口为底层 remember-me 实现提供了身份验证相关事件的充分通知,并在候选 Web 请求可能包含 cookie 并希望被记住时委托给该实现。 此设计允许任意数量的 remember-me 实现策略。 我们在上面已经看到 Spring Security 提供了两种实现。 我们将依次介绍这些。spring-doc.cadn.net.cn

TokenBasedRememberMeServices

此实现支持 Simple Hash-Based Token Approach 中描述的更简单的方法。TokenBasedRememberMeServices生成一个RememberMeAuthenticationToken,该 API 由RememberMeAuthenticationProvider. 一个key在此身份验证提供程序和TokenBasedRememberMeServices. 另外TokenBasedRememberMeServices需要一个 UserDetailsService,它可以从中检索用户名和密码以进行签名比较,并生成RememberMeAuthenticationToken以包含正确的GrantedAuthoritys. 应用程序应该提供某种 logout 命令,如果用户请求,该命令将使 cookie 失效。TokenBasedRememberMeServices还实现了 Spring Security 的LogoutHandler接口,因此可以与LogoutFilter以自动清除 Cookie。spring-doc.cadn.net.cn

在应用程序上下文中启用“记住我”服务所需的 bean 如下所示:spring-doc.cadn.net.cn

<bean id="rememberMeFilter" class=
"org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
<property name="rememberMeServices" ref="rememberMeServices"/>
<property name="authenticationManager" ref="theAuthenticationManager" />
</bean>

<bean id="rememberMeServices" class=
"org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService" ref="myUserDetailsService"/>
<property name="key" value="springRocks"/>
</bean>

<bean id="rememberMeAuthenticationProvider" class=
"org.springframework.security.authentication.RememberMeAuthenticationProvider">
<property name="key" value="springRocks"/>
</bean>

不要忘记添加您的RememberMeServicesimplementation 复制到UsernamePasswordAuthenticationFilter.setRememberMeServices()属性,包括RememberMeAuthenticationProviderAuthenticationManager.setProviders()list 中,然后添加RememberMeAuthenticationFilter放入您的FilterChainProxy(通常紧跟在UsernamePasswordAuthenticationFilter).spring-doc.cadn.net.cn

PersistentTokenBasedRememberMeServices

此类的使用方式与TokenBasedRememberMeServices,但还需要使用PersistentTokenRepository来存储令牌。 有两种标准实现。spring-doc.cadn.net.cn

数据库架构在上面的 持久令牌方法中进行了介绍。spring-doc.cadn.net.cn


1. 本质上,用户名不包含在 cookie 中,以防止不必要地暴露有效的登录名。在本文的评论部分对此进行了讨论。