记住我功能,这个是登入时常见的功能,就是用户在登入一次以后,勾选记住我功能按钮后,系统会记住用户一段时间,在这段时间内用户不应反复登入系统的操作;
简单说明一下:浏览器在用户登入的时候,发送认证请求给UsernamePassworAuthenticationFilter这个身份认证过滤器,或者是自己特定的过滤器,当我们的认证过滤器认证成功后会调用一个RemeberMeService的服务,这个服务里面有一个TokenRepository,这个会生成一个Token,然后将这个Token返回给浏览器并写入到Cookie里面,同时会将Token写入到数据库里面,这里Token和用户名是一一对应的,当我们的用户过了几天后在来请求我们的服务器,那么他就不需要登入了,在有效时间内可以直接访问受保护的服务,那么这些请求在经过过滤器链的时候会经过一个RememberMeAuthenticationFilter,这个过滤器的作用就是获取Cookie中的token,然后交给RemeberMeService,然后由RokenRepository到数据库中查询这个token在数据库中有没有记录,数据库中有token记录将对应的用户名取出来,取出用户名后会调用UserDetailsService,然后获取用户的信息放到SecurityContenx里面存储,然后用户就自动登入上,这就是记住我功能的基本流程!
RememberMeAuthenticationFilter
RememberMeAuthenticationFilter是位于过滤器里面的倒数第二个的位置上,前面是一些其他的认证过滤器,当其他的认证过滤器都无法认证用户信息的时候,RememberMeAuthorizationFilter会尝试做认证的操作!
记住我的原理差不多就是这样的!下面来具体实现!
在SpringSecurity配置类中注入数据源和UserDetailsService,数据源是用来插入、更新token等操作的,UserDetailsService是用来查出用户名后校验用户身份的操作,然后在添加Token持久化存储的Bean,在重写的configure方法中添加对应配置即可
服务端代码
@Autowired
private DataSource dataSource;//注入数据源
@Autowired
private UserDetailsService userDetailsService;//这里实际上就是将用户名取出来交给userDetailsService的操作
@Bean//Token持久化存储
public PersistentTokenRepository persistentTokenRepository(){
JdbcTokenRepositoryImpl tokenRepository=new JdbcTokenRepositoryImpl();//这个接口完成建表,查询,修改等操作
//public static final String 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)";
tokenRepository.setDataSource(dataSource);
tokenRepository.setCreateTableOnStartup(false);//启动的时候会自动建表--但是这里没有表已存在不建表的操作,所以表存在后不能再次开启
return tokenRepository;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
.formLogin()//这是开启表单登入的意思
.xxx
.xxx
.xxx
.and()
//记住我的配置核心
.rememberMe()//记住我功能开启
.tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(毫秒数)//记住我的时间--token的过期时间
.userDetailsService(userDetailsService)//最终拿到用户名后用userDetailsService去登入
.and()
}
表单界面代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<h2>标准登录页面</h2>
<h3>表单登录</h3>
<form action="/authentication/form" method="post">
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td>图形验证码:</td>
<td>
<input type="text" name="imageCode">
<img src="/code/image?width=200">
</td>
</tr>
<tr>
<td colspan='2'><input name="remember-me" type="checkbox" value="true" />记住我</td>
</tr>
<tr>
<td colspan="2"><button type="submit">登录</button></td>
</tr>
</table>
</form>
</body>
</html>