A place to hold mainly reading notes, and some technical stuff occasionally. 这里主要是一些读书笔记、感悟;还有部分技术相关的内容。
目录[-]
本系列教程,是作为团队内部的培训资料准备的。主要以实验的方式来体验 SpringSecurity
的各项Feature。
SpringSecurity
提供了开箱即用的remember-me
功能,就是长下面这样:
直接在5-SpringSecurity:RBAC及方法授权的项目 springboot-security-rbac
中进行实验 ,核心依赖为 Web
与 SpringSecurity
:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
直接在最后加一个配置:.and().rememberMe()
便开启了RememberMe
功能,此时再到登录页,就会看到有个可勾选的checkbox
。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/user/add").hasRole("dev")
.antMatchers("/user/query").hasAuthority("ROLE_test")
.antMatchers("/user/**").authenticated()
.anyRequest().permitAll() // Let other request pass
.and()
.formLogin()
.and()
.rememberMe();
}
填写账号、密码并勾选Remember me on this computer.
之后,先打开浏览器控制台,然后点击登录,可以观察到Cookie中除了JSESSIONID
之外,还多了一个remember-me
。
从.and().rememberMe()
这个配置项一直跟到源码AbstractRememberMeServices
类,可以看到有个encodeCookie(String[] cookieTokens)
方法,里面最后返回是一个Base64
编码的字符串。
protected String encodeCookie(String[] cookieTokens) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < cookieTokens.length; i++) {
try {
sb.append(URLEncoder.encode(cookieTokens[i], StandardCharsets.UTF_8.toString()));
}
catch (UnsupportedEncodingException ex) {
this.logger.error(ex.getMessage(), ex);
}
if (i < cookieTokens.length - 1) {
sb.append(DELIMITER);
}
}
String value = sb.toString();
sb = new StringBuilder(new String(Base64.getEncoder().encode(value.getBytes())));
while (sb.charAt(sb.length() - 1) == '=') {
sb.deleteCharAt(sb.length() - 1);
}
return sb.toString();
}
这里先利用线上的工具进行Base64
解码:
接着,再用Java
自带的工具类解码:
可以观察到解码后的字符串一致,由三部分构成:用户名:时间戳:类似MD5
或去了连词符的UUID
,其中时间戳经过计算是14天,这在源码中得到了证实。具体规则经过查阅官方文档,是这样的:
Base64
编码,是选出64个字符作为一个基本字符集(A-Z,a-z,0-9,+,/,再加上作为补充的”=”,实际是65个字符),其它所有符号都按照规则转换成这个字符集中的字符。正常编码转成Base64
编码,满足3 * 8 = 24 = 4 * 6
。即每3个字节的正常编码可以转成由4个字节组成的正常编码。编码规则如下:
码表(参考RFC2045
):
Note:如果要编码的字节数不能被3整除,最后会多出1个或2个字节。
If you have any questions or any bugs are found, please feel free to contact me.
Your comments and suggestions are welcome!