17. Remember-Me Authentication
17.1 Overview
记住我或持久登录身份验证是指网站能够记住会话之间主体的身份。这通常是通过向浏览器发送一个cookie来实现的,在以后的会话中会检测到该cookie,并导致自动登录。Spring Security为这些操作的发生提供了必要的挂钩,并且有两个具体的记忆实现。一种使用哈希来保持基于cookie的令牌的安全性,另一种使用数据库或其他持久存储机制来存储生成的令牌。
请注意,这两种实现都需要一个用户详细信息服务。如果您使用的身份验证提供程序不使用用户详细信息服务(例如,LDAP提供程序),那么除非您的应用程序上下文中也有一个用户详细信息服务bean,否则它将不起作用。
17.2 Simple Hash-Based Token Approach(简单的基于哈希的令牌方法)
这种方法使用哈希来实现一个有用的remember-me策略。本质上,一个cookie在成功的交互认证后被发送到浏览器,cookie的组成如下:
因此,只要用户名、密码和密钥不变,remember-me令牌仅在指定的时间段内有效。值得注意的是,这有一个潜在的安全问题,因为在令牌过期之前,任何用户代理都可以使用捕获的“记住我”令牌。这是与摘要式身份验证相同的问题。如果委托人知道令牌已被捕获,他们可以轻松地更改密码,并立即使所有有问题的“记住我”令牌无效。如果需要更重要的安全性,您应该使用下一节中描述的方法。或者,记住我的服务根本就不应该使用。
如果您熟悉名称空间配置一章中讨论的主题,您可以通过添加<remember-me>元素来启用记住我身份验证:
用户详细信息服务通常会自动选择。如果您的应用程序上下文中有多个,您需要指定哪个应该与user-service-ref属性一起使用,其中该值是您的UserDetailsService bean的名称。
17.3 Persistent Token Approach(持久令牌方法)
这种方法是基于文章 http://jaspan.com/improved_persistent_login_cookie_best_practice 有一些小的修改 [12]. 若要使用命名空间配置的这种方法,你应该提供一个数据源引用:
该数据库应该包含一个持久登录表,该表使用以下SQL(或等效语言)创建:
17.4 Remember-Me Interfaces and Implementations(记住我的界面和实现)
Remember-me是用于 UsernamePasswordAuthenticationFilter,并通过AbstractAuthenticationProcessingFilter超类的钩子实现。 它也用在BasicAuthenticationFilter中。钩子将在适当的时候调用一个具体的RememberMeServices 。界面如下所示:
请参考JavaDocs获得什么方法都做了更充分的讨论,不过注意在这个阶段,AbstractAuthenticationProcessingFilter仅调用loginFail()和loginSuccess()方法。每当SecurityContextHolder不包含身份验证时,都会由RememberMeAuthenticationFilter调用autoLogin()方法。因此,这个接口为底层的remember-me实现提供了足够的身份验证相关事件的通知,并在候选web请求可能包含cookie并希望被记住时委托给该实现。这种设计允许任何数量的记住我的实现策略。上面我们已经看到,Spring Security提供了两种实现。我们将依次看这些。
17.4.1 TokenBasedRememberMeServices(基于令牌的RememberMe服务)
该实现支持 Section 17.2, “Simple Hash-Based Token Approach”中描述的更简单的方法。TokenBasedRememberMeServices 生成一个RememberMeAuthenticationToken,由RememberMeAuthenticationProvider处理。此身份验证提供程序和TokenBasedRememberMeServices 之间共享一个密钥。此外,TokenBasedRememberMeServices需要一个用户详细信息服务,它可以从该服务中检索用户名和密码以进行签名比较,并生成包含含正确GrantedAuthority的一个UserDetailsService。如果用户需要的话,应用程序应提供某种注销命令使cookie无效。TokenBasedRememberMeServices 还实现了Spring Security的LogoutHandler接口,因此可以与LogoutFilter一起使用来自动清除cookie。
应用程序上下文中启用remember-me 服务所需的beans如下:
不要忘记将您的RememberMeServices实现添加到您的usernamepasswordAuthenticationFilter . setrememberMeaservices()属性中,将rememberMeauthenticationProvider包括在您的authenticationManager . SetProviders()列表中,并将RememberMeAuthenticationFilter添加到您的过滤器链代理中(通常紧接在您的usernamepasswordAuthenticationFilter之后)。
17.4.2 PersistentTokenBasedRememberMeServices(基于持久令牌的RememberMe服务)
此类的使用方式与TokenBasedRememberMeServices相同,但还需要配置一个PersistentTokenRepository来存储令牌。有两种标准实现。
InMemoryTokenRepositoryImpl 这是只用来测试。
JdbcTokenRepositoryImpl 其存储在数据库中的令牌。
数据库模式在上文Section 17.3, “Persistent Token Approach”中有所描述。
本质上,用户名不包括在cookie中,以防止不必要地暴露有效的登录名。本文的评论部分对此进行了讨论。