在许多应用软件我们都可以看到 RememberMe
选项。如果我们勾选的话,下次访问就无须再登录。那么Spring Security是怎么实现 RememberMe
功能呢?我们基于数据库存储token的方式来实现 RememberMe
。
RememberMe配置
这里配置是针对第4章改造的。这里主要替换 UserWebSecurityConfig
的 configure
方法
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/admin/**").hasAnyRole("ADMIN")
.antMatchers("/hello2/").fullyAuthenticated()
.antMatchers("/rememberMe/").rememberMe()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll()
.and()
.rememberMe()
.tokenRepository(jdbcTokenRepository()).and()
.csrf().disable();
}
// 新增
@Autowired
private DataSource dataSource;
// 新增
public JdbcTokenRepositoryImpl jdbcTokenRepository() {
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
return jdbcTokenRepository;
}
数据库表
我们需要新增 persistent_logins
表。表的创建语句在 JdbcTokenRepositoryImpl
已经内置。
create table persistent_logins (
username varchar(64) not null,
series varchar(64) primary key,
token varchar(64) not null,
last_used timestamp not null
);
至此,RememberMe
功能就开发完成了。那么它是如何实现呢?
原理解析
涉及到的类
这里主要涉及到了 RememberMeAuthenticationFilter
过滤器 、 RememberMeServices
接口和他的实现类。
从登录地方开始
为什么我们勾选了就可以了,所以我们从登录地方开始追踪。我们可以发现 AbstractAuthenticationProcessingFilter
类完成登录时,我们会调用该类的 successfulAuthentication()
方法,然后这个方法又会调用 rememberMeServices#loginSuccess
方法进行处理。
rememberMeServices#loginSuccess
是实现 RememberMe
功能的入口。主要逻辑是,首先判断请求是否有 remember-me
参数并且该参数的值必须是 (true、on、yes、1)的其中一项。然后进入 AbstractRememberMeServices#onLoginSuccess
的方法,生成Token,存储Token到数据库,最后把Token写入 response.addCookie(cookie)
。
RememberMeAuthenticationFilter 过滤器
上面登录成功后,就算我们重新打开浏览器,再次访问也无须进行登录。这是怎么做到呢?大致实现时序图如下所示。
备注
本系列都是学习《深入浅出Spring Security》的笔记