《Spring Security》第十四章 Remember-Me Authentication

第十四章 Remember-Me Authentication

Remember-Me 或者 persistent-login 验证是指网站能够在会话之间记住主体的身份。通常是向浏览器发送 cookie 来实现的,并且在后面的会话中,会去检测 cookie 并进行自动登录。

Spring Security 提供了两种方式来实现具体的 remember-me 操作,一种是使用 hash 来保护基于 cookie 令牌的安全性,另一种是使用数据库或其他持久存储机制来存储生成的令牌。

这两种方式都需要 UserDetailsService,否则身份验证程序将无法工作。

一、Simple Hash-Based Token Approach

使用散列来实现一个 remember-me 策略,在身份验证成功后,cookie会被发送到浏览器,其组成如下:

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

在令牌的有效期内,用户名、密码、秘钥不能更改。这种方式存在一个安全问题,因为 remember-me 令牌可以从任何用户代理使用,直到令牌过期为止。那么如果一个主体知道了令牌已经被 captured,那么可以很容易地更改密码,并使所有的 remember-me 令牌失效。

Alternatively remember-me services should simply not be used at all. 因此,hash-based remember-me 不应该被使用。

二、Persistent Token Approach

持久令牌的方法,需要为 remember-me 配置一个持久化数据源,如下:

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

该数据库需要包含一个 “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 通常与 UsernamePasswordAuthenticationFilter 一起使用,在通过用户名、密码方式登录时,选择是否记住用户密码。并且通过 AbstractAuthenticationProcessingFilter 父类的钩子来实现。

它也可以与 BasicAuthenticationFilter 一起使用,钩子会在适当的时候调用一个具体的 RememberMeServices 服务。

1. RememberMeServices Interface

以下是 RememberMeServices 接口的内容:

// 该接口为 remember-me 提供了基础的,与认证相关的事件通知
public interface RememberMeServices {

    Authentication autoLogin(HttpServletRequest request, HttpServletResponse response);

    void loginFail(HttpServletRequest request, HttpServletResponse response);

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

在 AbstractAuthenticationProcessingFilter 中只调用了 loginFail 和 loginSuccess,只要 SecurityContextHolder 中不包含身份验证,那么 RememberMeAuthenticationFilter 就会调用 autoLogin() 方法。

2. TokenBasedRememberMeServices Implements

TokenBasedRememberMeService 生成一个 RememberMeAuthenticationToken,并交给 RememberMeAuthenticationProvider 进行处理。

在 TokenBasedRememberMeService 的构造中,需要两个参数,一个是 key,另一个是 UserDetailsService,用于比较用户名和密码,并生成 RememberMeAuthenticationToken 来包含正确的 GrantedAuthority。

该 Service 还实现了 LogoutFilter,因此可以使用 LogoutFilter 自动清除 cookie。

3. PersistentTokenBasedRememberMeServices

与 TokenBasedRememberMeServices 一样,但是需要一个 PersistentTokenRepository 来存储这些令牌。

PersistentTokenRepository 有两个具体实现:

  1. InMemoryTokenRepositoryImpl
  2. JdbcTokenRepositoryImpl
文章作者: koral
文章链接: http://luokaiii.github.io/2019/07/23/读书笔记/《SpringSecurity》/14.RememberMeAuth/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自