对于最新的稳定版本,请使用 Spring Security 6.5.3! |
记住我身份验证
概述
记住我或持久登录身份验证是指网站能够在会话之间记住主体的身份。 这通常是通过向浏览器发送 cookie 来实现的,在未来的会话中检测到 cookie 并导致自动登录。 Spring Security 为执行这些作提供了必要的钩子,并具有两个具体的 remember-me 实现。 一种使用哈希来保护基于 cookie 的Tokens的安全性,另一种使用数据库或其他持久存储机制来存储生成的Tokens。
请注意,这两种实现都需要一个UserDetailsService
.
如果您使用的身份验证提供程序不使用UserDetailsService
(例如,LDAP 提供程序),否则它将不起作用,除非您还有UserDetailsService
bean 的 bean 中。
简单的基于哈希的Tokens方法
这种方法使用哈希来实现有用的记住我策略。 本质上,在成功进行交互式身份验证后,Cookie 会发送到浏览器,其组成如下:
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
因此,记住我Tokens仅在指定期限内有效,前提是用户名、密码和密钥不变。 值得注意的是,这存在潜在的安全问题,因为捕获的记住我Tokens可以从任何用户代理使用,直到Tokens过期为止。 这与摘要式身份验证的问题相同。 如果委托人知道Tokens已被捕获,他们可以轻松更改密码并立即使所有已发布的记住我Tokens失效。 如果需要更重要的安全性,则应使用下一节中所述的方法。 或者,根本不应该使用记住我服务。
如果您熟悉命名空间配置一章中讨论的主题,则只需添加<remember-me>
元素:
<http>
...
<remember-me key="myAppKey"/>
</http>
这UserDetailsService
通常会自动选择。
如果您的应用程序上下文中有多个,则需要指定应将哪个与user-service-ref
属性,其中值是您的名称UserDetailsService
豆。
持久Tokens方法
此方法基于文章 http://jaspan.com/improved_persistent_login_cookie_best_practice,并进行了一些细微的修改[1]. 要将此方法与命名空间配置一起使用,您需要提供数据源引用:
<http>
...
<remember-me data-source-ref="someDataSource"/>
</http>
数据库应包含persistent_logins
表,使用以下 SQL(或等效 SQL)创建:
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 与UsernamePasswordAuthenticationFilter
,并通过AbstractAuthenticationProcessingFilter
超类。
它也用于BasicAuthenticationFilter
.
钩子将调用一个具体的RememberMeServices
在适当的时候。
界面如下所示:
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()
方法由RememberMeAuthenticationFilter
每当SecurityContextHolder
不包含Authentication
.
因此,此接口为底层 remember-me 实现提供了与身份验证相关的事件的充分通知,并在候选 Web 请求可能包含 cookie 并希望被记住时委托给实现。
这种设计允许任意数量的记住我实现策略。
我们在上面看到 Spring Security 提供了两种实现。
我们将依次查看这些。
基于 Token的RememberMe服务
此实现支持基于简单哈希的Tokens方法中描述的更简单的方法。TokenBasedRememberMeServices
生成一个RememberMeAuthenticationToken
,由RememberMeAuthenticationProvider
.
一个key
在此身份验证提供程序和TokenBasedRememberMeServices
.
另外TokenBasedRememberMeServices
需要一个 UserDetailsService,它可以从中检索用户名和密码以进行签名比较,并生成RememberMeAuthenticationToken
以包含正确的GrantedAuthority
s.
应用程序应提供某种注销命令,如果用户请求此命令,则该命令使 cookie 无效。TokenBasedRememberMeServices
还实现了 Spring Security 的LogoutHandler
接口,因此可以与LogoutFilter
自动清除 cookie。
应用程序上下文中启用 remember-me 服务所需的 bean 如下所示:
<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>
不要忘记添加您的RememberMeServices
实现到您的UsernamePasswordAuthenticationFilter.setRememberMeServices()
属性,包括RememberMeAuthenticationProvider
在你的AuthenticationManager.setProviders()
list,然后添加RememberMeAuthenticationFilter
进入您的FilterChainProxy
(通常紧接在您UsernamePasswordAuthenticationFilter
).
PersistentTokenBasedRememberMe服务
此类的使用方式与TokenBasedRememberMeServices
,但它还需要配置一个PersistentTokenRepository
以存储Tokens。
有两种标准实现。
-
InMemoryTokenRepositoryImpl
仅用于测试。 -
JdbcTokenRepositoryImpl
将Tokens存储在数据库中。
数据库模式在上面的持久Tokens方法中进行了描述。