实际运行过ch03的朋友可能发现Remember Me有个缺陷,当我们重启服务器后Remember Me将失效。这是因为用户的session已经丢失了,这对用户来说是非常不方便的。系统其实间接地暴露了自己的运维信息,这是非常不应该的。
Spring Security提供了Remember Me Toke持久化技术来解决这个问题。RememberMeServices默认实现类是TokenBasedRememberMeServices,该类将Remember Me Token存储到内存,当重启服务后,内存数据丢失,无法验证用户的有效Token。
PersistentTokenBasedRememberMeServices是RememberMeServices的另一个实现,其通过PersistentTokenRepository将Remember Me Token存储到数据库。当用户再次登入后,通过对比cookie和数据库就可以完成认证过程。
只需要通过修改WebSecurityConfigurerAdapter即可以使Spring Security启动PersistentTokenBasedRememberMeServices。
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/assets/**").permitAll()
.antMatchers("/**").hasRole("USER")
.and().formLogin().loginPage("/login.jsp").permitAll().loginProcessingUrl("/login")
//自动识别tokenRepository类型,启用PersistentTokenBasedRememberMeServices
.and().rememberMe().tokenRepository(persistentTokenRepository())
.and().csrf().disable();
}
/**
* 可持久化的cookie token服务
*
* @return
*/
@Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
tokenRepository.setDataSource(dataSource);
return tokenRepository;
}
创建MySql数据库脚本
-- ----------------------------
-- Table structure for persistent_logins
-- ----------------------------
DROP TABLE IF EXISTS `persistent_logins`;
CREATE TABLE `persistent_logins` (
`username` varchar(64) NOT NULL,
`series` varchar(64) NOT NULL,
`token` varchar(64) NOT NULL,
`last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`series`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS=1;
启动服务,登录用户并选择Remember Me。查询数据库,就可以看到persistent_logins表中增加了一条记录。
Paste_Image.png
重启浏览器,不用认证直接登录功能正常。
重启服务器,刷新用户界面,不用认证直接登录功能正常。
用户友好性大大提高,不需要用户因服务器重启而重新认证。
PersistentTokenBasedRememberMeServices为每个用户创建一个唯一的series,用户在继续认证和交互时要使用series来查找对应的token,与存储在cookie中的Token进行对比完成认证。series和token都是随机生成的,被暴力破解的难度大大降低。
代码示例:https://github.com/wexgundam/spring.security/tree/master/ch07
网友评论