源码地址:
https://github.com/pony-maggie/spring-security-learn
remember me(记住我)这个功能大家都很熟悉,现在各大网站用得很普遍。当我们勾选了这个功能并且登录成功后,在一定的时间内再次登录就不用输入用户名和密码了,即使浏览器退出重新打开也是如此。
本文会实现一个基本的remember me功能,并且简单分析下它的实现原理。
首先,前端登录页面增加勾选按钮,这个简单,
<div class="checkbox">
<label><input type="checkbox" id="rememberme" name="remember-me"/>记住我label>
div>
接着我们的配置也需要增加一些内容,
.and()
.rememberMe()
.userDetailsService(myUserDetailsService)
.tokenRepository(persistentTokenRepository()) //数据访问层,token持久化方案
.tokenValiditySeconds(60)//token有效期,这里配置60秒
input标签中这个name很重要,这个属性必须有,并且名字一定要是remember-me,因为这是spring security默认识别的名字。当然这个名字可以自定义,只要在配置中加入remember-me-parameter选项指定自己喜欢的名字即可。
.rememberMe()
.rememberMeParameter("my-remember-me")
userDetailsService用来指定获取用户信息的服务,因为token验证最终是要拿到用户信息的。
persistentTokenRepository是指明token的持久化方案。remember me功能是基于token,持久化方案有两种,一种基于内存,使用的是InMemoryTokenRepositoryImpl,一种基于数据库,使用的是JdbcTokenRepositoryImpl。这里我选择基于数据库的方式。
//datasource的配置是通过配置文件加载过来的
@Autowired
DataSource dataSource;
//注入BCryptPasswordEncoder,不然会报错
@Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
PersistentTokenRepository persistentTokenRepository(){
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
return jdbcTokenRepository;
}
MyUserDetailsService跟第二章是一样的,功能就是从数据库获取用户信息。
我这里继续使用第二章的数据库配置。另外还需要在数据库里新建一张名为persistent_logins 的表,这是JdbcTokenRepositoryImpl缺省要使用的存放token的表,建表语句如下:
create table persistent_logins (username varchar(64) not null default '', series varchar(64) primary key, token varchar(64) not null , last_used timestamp not null)
也可以在代码中自动建表,首次启动时使用:
jdbcTokenRepository.setCreateTableOnStartup(true);
然后再把这一行注释掉即可。
一般情况下,当用户主动点击注销时是不希望下次直接登录,所以我们需要在注销的时候删除cookie。
.and().logout().permitAll()
.logoutSuccessHandler(logoutSuccessHandler())
.deleteCookies("remember-me")
启动工程,进行如下测试:
如果在登录时勾选了Remember Me,登录成功后,会在浏览器中生成一个Cookie项,有效期就是我们通过tokenValiditySeconds指定的时间,其值是一个加密字符串。
[外链图片转存失败(img-QfAsypZ7-1563097741379)(./images/cookie.jpg)]
基本原理如下图所示:
当用户发起认证请求,会通过UsernamePasswordAuthenticationFilter进行认证,成功之后,可以调用SpringSecurity提供的RememberMeService生成一个Token并将它写入浏览器的Cookie中,同时TokenRepository会将Token放入数据库中。
下次浏览器请求的时候,会经过RememberMeAuthenticationFiler,在这个filter里面会读取Cookie中的Token,然后去数据库中查找是否有相应的Token,找到token后再根据对应的用户名通过UserDetailsService获取用户的信息。
参考:
https://www.cnblogs.com/xuwenjin/p/9933218.html
https://docs.spring.io/spring-security/site/docs/5.2.0.M3/reference/htmlsingle/