前面介绍的几种 RememberMe 实现方式,全部都是基于 RememberMeServices 接口的实现 TokenBasedRememberMeServices。此实现是将 username、过期时间、password、key等按照一定的规则组合之后取MD5值,之后将此值存在浏览器的Cookie中。
大部分网站的RememberMe 实现方式都是基于此。但是,将用户的 password 存储在浏览器的 Cookie 中, 始终存在隐患,即使难以实现。因此,Spring Security 框架提供了另外一种实现方式,基于 数据库 和 Cookie 的实现方式:PersistentTokenBasedRememberMeServices。
此实现方式无论是 数据库 和 Cookie,都不存储 password 等敏感信息。但是,如果用户的密码、状态等敏感信息发生改变,需要与 PersistentTokenBasedRememberMeServices 联动,如删除该用户之前的token等。关于这一点,PersistentTokenBasedRememberMeServices 类的注释写的很明白。
User management such as changing passwords, removing users and setting user status should be combined with maintenance of the user's persistent tokens.* </p>
既然如此,那我们就把 RememberMe 的实现方式换成 PersistentTokenBasedRememberMeServices 吧。只需修改一下 Spring Security 的部分配置即可。
protected void configure(HttpSecurity http) throws Exception {
http
......
.rememberMe()
.key(DEFAULT_REMEMBER_ME_KEY)
.rememberMeServices(persistentTokenBasedRememberMeServices())
......
}
private RememberMeServices persistentTokenBasedRememberMeServices() {
return new PersistentTokenBasedRememberMeServices(DEFAULT_REMEMBER_ME_KEY, userDetailsService(), persistentTokenRepository());
}
private PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setJdbcTemplate(jdbcTemplate);
return jdbcTokenRepository;
}
关于数据结构,有两种创建方式。
其一,交给 Spring Security 框架自动创建。此时,修改一下 PersistentTokenRepository 实现的配置,暴露为 Bean,且设置参数 createTableOnStartup 为 true。
@Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setCreateTableOnStartup(true);
jdbcTokenRepository.setJdbcTemplate(jdbcTemplate);
return jdbcTokenRepository;
}
启动系统时,Spring Security 框架会自动创建数据结构。
protected void initDao() {
if (createTableOnStartup) {
getJdbcTemplate().execute(CREATE_TABLE_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)
此两种方式均可,但是,第一种方式如果是在第一次启动且创建过数据结构后,再启动时,会抛出异常。因此,推荐采用第二种方式。
好了,我们启动系统,依然访问系统首页,跳转到登录页后,输入用户名、密码、验证码、勾选 记住我 选项,登录系统。查看 persistent_logins 表,当前用户的token信息已成功记录。
关闭浏览器,直接访问系统首页,此时,仍然可以直接访问,并没有重定向到登录页,无需输入用户名、密码、验证码。相同的,重启应用之后,同样可以直接访问系统首页,也无需重新登录。
其它详细源码,请参考文末源码链接,可自行下载后阅读。
我是银河架构师,十年饮冰,难凉热血,愿历尽千帆,归来仍是少年!
如果文章对您有帮助,请举起您的小手,轻轻【三连】,这将是笔者持续创作的动力源泉。当然,如果文章有错误,或者您有任何的意见或建议,请留言。感谢您的阅读!
源码
github
https://github.com/liuminglei/SpringSecurityLearning/tree/master/35
gitee
https://gitee.com/xbd521/SpringSecurityLearning/tree/master/35