说明
(1)JDK版本:1.8
(2)Spring Boot 2.0.6
(3)Spring Security 5.0.9
(4)Spring Data JPA 2.0.11.RELEASE
(5)hibernate5.2.17.Final
(6)MySQLDriver 5.1.47
(7)MySQL 8.0.12
前言
在上一节我们介绍了Spring Security中”记住我”的两种方案,那么本节就先介绍一下其中的一种:基于简单加密token的方式。
一、编码分析
当用户选择了记住我成功登录后,Spring Security 将会生成一个 cookie 发送给客户端浏览器。cookie 值由如下方式组成:
base64(username+":"+expirationTime+":"+md5Hex(username+":"+expirationTime+":"+password+":"+key))
从上面的加密串,对于编码有一个简单的分析:
(1)需要有一个key: 用来防止修改token的一个key。
(2) key怎么使用:HttpSecurity在配置开启rememberMe()的时候可以执行key(),这里还需要制定rememberMeServices的具体实现方法,在此方法上可以指定加密方式为「简单加密token的方式」,另外可以指定cookie的过期时间,再者就是在网页前端表单“记住我”的参数名称。
通过这个分析,我们可以理出编码的思路:
(1)需要有一个rememberMeServices方法(即记住我的具体的实现方法):这里可以使用Spring Security提供的TokenBasedRememberMeServices进行配置,在这里设置cookie的过期时间和前端“记住我“复选框的参数名,不设置的话,默认为remember-me。
(2)在Spring Security配置记住我:在configure()方法中进行“记住我“的配置。
(3)编写前端代码:前端代码只需要添加一个“记住我“的checkbox即可。
二、编码实现
2.1 定义key
这个key这里只是在WebSecurityConfig定义了一个全局变量,最好的方式应该是在application.properties进行配置,然后在代码中进行引用,这里为了代码的理解简单,直接配置:
/** 用来防止token被修改的key */
private String rememberMeKey = "wuqian2019";
2.2 rembermeServices的实现
定义rememberServices的具体实现,
(1)[必须]需要指定上面配置的key和userDetailService。
(2)[可选]需要配置cookie的过期时间,默认过时时间1209600秒,即2个星期。
(3)[可选]前端checkbox的参数名,默认为remember-me。
具体代码如下:
@Bean
public RememberMeServices rememberMeServices() {
System.out.println("WebSecurityConfig.tokenBasedRememberMeServices()="+customUserDetailService);
TokenBasedRememberMeServices tbrms = new TokenBasedRememberMeServices(rememberMeKey, customUserDetailService);
// [可选]需要配置cookie的过期时间,默认过时时间1209600秒,即2个星期。这里设置cookie过期时间为1天
tbrms.setTokenValiditySeconds(60 * 60 * 24 * 1);
// 设置checkbox的参数名为rememberMe(默认为remember-me),
//注意如果是ajax请求,参数名不是checkbox的name而是在ajax的data里
//tbrms.setParameter("rememberMe");
return tbrms;
}
2.3 开启remember me功能
配置WebSecurityConfig类中的configure(HttpSecurityhttp)方法,开启remember me功能:
http.authorizeRequests() // 定义哪些URL需要被保护、哪些不需要被保护
.antMatchers("/login").permitAll()// 设置所有人都可以访问登录页面
.antMatchers("/","/index").permitAll()
.antMatchers("/test/**","/test1/**").permitAll()
.antMatchers("/res/**/*.{js,html}").permitAll()
.anyRequest().access("@authService.canAccess(request,authentication)")
//.anyRequest().authenticated() // 任何请求,登录后可以访问
.and().formLogin().loginPage("/login")
//设置记住我 .and().rememberMe().key(rememberMeKey).rememberMeServices(rememberMeServices())
//设置并发session个数.
.and().sessionManagement().maximumSessions(1)
;
这里核心的代码是:
.and().rememberMe().key(rememberMeKey)
.rememberMeServices(rememberMeServices())
2.4登录页login.html上添加一个CheckBox控件
在登录页login.html上添加一个CheckBox控件:
<form th:action="@{/login}" method="post">
<div><label> 用户名 : <input type="text" name="username"/> </label></div>
<div><label> 密码: <input type="password" name="password"/> </label></div>
<div><label> <input type="checkbox" name="remember-me"/> 记住我</label></div>
<div><input type="submit" value="登录"/></div>
</form>
2.5 测试
访问登录页面:
登录成功之后,可以看到浏览器的cookie中多了一个cookie:
这时候说明我们配置的remember-me已经开始工作了。