Remember-Me 身份验证
Remember-me 或 persistent-login 身份验证是指 Web 站点能够在会话之间记住主体的身份。 这通常是通过向浏览器发送 cookie 来实现的,该 cookie 在将来的会话中被检测到并导致自动登录。 Spring Security 为这些操作的发生提供了必要的钩子,并且有两个具体的 remember-me 实现。 一种使用哈希来保持基于 Cookie 的令牌的安全性,另一种使用数据库或其他持久性存储机制来存储生成的令牌。
请注意,这两种实现都需要 .
如果使用的身份验证提供程序不使用 (例如,LDAP 提供程序),则除非应用程序上下文中也有 Bean,否则它将无法工作。UserDetailsService
UserDetailsService
UserDetailsService
简单的基于哈希的代币方法
这种方法使用哈希来实现有用的 remember-me 策略。 实质上,在成功进行交互式身份验证后,会向浏览器发送一个 Cookie,该 Cookie 的组成如下:
base64(username + ":" + expirationTime + ":" + algorithmName + ":"
algorithmHex(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
algorithmName: The algorithm used to generate and to verify the remember-me token signature
“记住我”令牌仅在指定的时间段内有效,并且仅当用户名、密码和密钥未更改时有效。 值得注意的是,这存在潜在的安全问题,因为捕获的 remember-me 令牌可以从任何用户代理使用,直到令牌过期。 这与摘要式身份验证的问题相同。 如果委托人知道令牌已被捕获,他们可以轻松更改密码并立即使所有已颁发的 remember-me 令牌失效。 如果需要更重要的安全性,则应使用下一节中描述的方法。 或者,根本不应该使用 remember-me 服务。
如果您熟悉命名空间配置一章中讨论的主题,则可以通过添加以下元素来启用记住我身份验证:<remember-me>
<http>
...
<remember-me key="myAppKey"/>
</http>
通常会自动选择。
如果应用程序上下文中有多个 bean,则需要指定应将哪个 bean 与属性一起使用,其中 value 是 bean 的名称。UserDetailsService
user-service-ref
UserDetailsService
持久令牌方法
此方法基于文章改进的持久性登录 Cookie 最佳实践,并进行了一些细微的修改[1]. 要将此方法与命名空间配置一起使用,您需要提供数据源引用:
<http>
...
<remember-me data-source-ref="someDataSource"/>
</http>
数据库应包含一个表,该表使用以下 SQL(或等效项)创建:persistent_logins
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 与超类中的钩子一起使用并通过 hooks 实现。
它也在 中使用。
钩子在适当的时间调用 具体 。
下面的清单显示了该接口:UsernamePasswordAuthenticationFilter
AbstractAuthenticationProcessingFilter
BasicAuthenticationFilter
RememberMeServices
Authentication autoLogin(HttpServletRequest request, HttpServletResponse response);
void loginFail(HttpServletRequest request, HttpServletResponse response);
void loginSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication successfulAuthentication);
有关这些方法的作用的更全面讨论,请参阅 RememberMeServices
的 Javadoc,但请注意,在此阶段,仅调用 and 方法。
每当 不包含 .
因此,此接口为底层的 remember-me 实现提供了与身份验证相关的事件的充分通知,并在候选 Web 请求可能包含 cookie 并希望被记住时委托给该实现。
此设计允许任意数量的 remember-me 实现策略。AbstractAuthenticationProcessingFilter
loginFail()
loginSuccess()
autoLogin()
RememberMeAuthenticationFilter
SecurityContextHolder
Authentication
我们之前已经看到 Spring Security 提供了两种实现。 我们依次查看这些内容。
TokenBasedRememberMeServices
此实现支持 Simple Hash-Based Token Approach 中描述的更简单的方法。 生成一个 ,该 由 处理。
A 在此身份验证提供程序和 .
此外,还需要一个 ,它可以从中检索用户名和密码以进行签名比较,并生成 以包含正确的实例。 还实现了 Spring Security 的接口,以便可以使用它来自动清除 cookie。TokenBasedRememberMeServices
RememberMeAuthenticationToken
RememberMeAuthenticationProvider
key
TokenBasedRememberMeServices
TokenBasedRememberMeServices
UserDetailsService
RememberMeAuthenticationToken
GrantedAuthority
TokenBasedRememberMeServices
LogoutHandler
LogoutFilter
默认情况下,此实现使用 SHA-256 算法对令牌签名进行编码。
为了验证令牌签名,将解析并使用从中检索到的算法。
如果不存在,则将使用默认匹配算法,即 SHA-256。
您可以为签名编码和签名匹配指定不同的算法,这允许用户安全地升级到不同的编码算法,同时在没有旧算法的情况下仍能够验证旧算法。
为此,您可以将自定义指定为 Bean 并在配置中使用它。algorithmName
algorithmName
algorithmName
TokenBasedRememberMeServices
-
Java
-
XML
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http, RememberMeServices rememberMeServices) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.rememberMe((remember) -> remember
.rememberMeServices(rememberMeServices)
);
return http.build();
}
@Bean
RememberMeServices rememberMeServices(UserDetailsService userDetailsService) {
RememberMeTokenAlgorithm encodingAlgorithm = RememberMeTokenAlgorithm.SHA256;
TokenBasedRememberMeServices rememberMe = new TokenBasedRememberMeServices(myKey, userDetailsService, encodingAlgorithm);
rememberMe.setMatchingAlgorithm(RememberMeTokenAlgorithm.MD5);
return rememberMe;
}
<http>
<remember-me services-ref="rememberMeServices"/>
</http>
<bean id="rememberMeServices" class=
"org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService" ref="myUserDetailsService"/>
<property name="key" value="springRocks"/>
<property name="matchingAlgorithm" value="MD5"/>
<property name="encodingAlgorithm" value="SHA256"/>
</bean>
在应用程序上下文中需要以下 bean 才能启用“记住我”服务:
-
Java
-
XML
@Bean
RememberMeAuthenticationFilter rememberMeFilter() {
RememberMeAuthenticationFilter rememberMeFilter = new RememberMeAuthenticationFilter();
rememberMeFilter.setRememberMeServices(rememberMeServices());
rememberMeFilter.setAuthenticationManager(theAuthenticationManager);
return rememberMeFilter;
}
@Bean
TokenBasedRememberMeServices rememberMeServices() {
TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices();
rememberMeServices.setUserDetailsService(myUserDetailsService);
rememberMeServices.setKey("springRocks");
return rememberMeServices;
}
@Bean
RememberMeAuthenticationProvider rememberMeAuthenticationProvider() {
RememberMeAuthenticationProvider rememberMeAuthenticationProvider = new RememberMeAuthenticationProvider();
rememberMeAuthenticationProvider.setKey("springRocks");
return rememberMeAuthenticationProvider;
}
<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>
请记住将 implementation 添加到 property 中,将 包含在 list 中,并添加到 your (通常紧跟在 your 之后)。RememberMeServices
UsernamePasswordAuthenticationFilter.setRememberMeServices()
RememberMeAuthenticationProvider
AuthenticationManager.setProviders()
RememberMeAuthenticationFilter
FilterChainProxy
UsernamePasswordAuthenticationFilter
PersistentTokenBasedRememberMeServices
您可以按照与 相同的方式使用此类,但还需要将其配置为 a 以存储令牌。TokenBasedRememberMeServices
PersistentTokenRepository
-
InMemoryTokenRepositoryImpl
仅用于测试。 -
JdbcTokenRepositoryImpl
它将令牌存储在数据库中。
有关数据库架构,请参阅 Persistent Token Approach。