持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第19天,点击查看活动详情
Spring Security之RememberMe
RememberMe应该是我们日常开发中一个非常常见的需求,在很多软件的登录界面,都会有一个记住记住密码或者自动登录等类似勾选框,一般来说,可以依赖Session来保持登录状态,而Session依赖于Cookie,如果浏览器关闭后重新打开,会话就会丢失,用户需要重新登录。有了这个功能后,我们访问软件或者网站只要登录了一次,即使是关闭了浏览器再重新打开,登录状态还依然有效。这个需求的的实现,就可以依赖于Spring Security的RemenmberMe。
1. RememberMe原理分析。
1.1 RememberMe 简介
RememberMe这个功能非常常见,最开始我认为的RememberMe功能就是把用户名/密码用Cookie保存在浏览器中,下次登录时不用再次输入用户名/密码。但是,这个理解大致是差不多的,但是显然缺乏安全保障,Spring Security的RememberMe还是通过服务器进行实现的。传统的登录方式基于Session 会话,一旦用户关闭浏览器重新打开,就要再次登录,这样太过于繁琐,没有便利性。如果能有一种机制,即使是用户关闭了浏览器之后再打开,依旧可以保持登录的状态,这样就会方便很多,RememberMe就是为了解决这一需求而生的。 RememberMe的具体实现思路就是通过Cookie来记录当前用户身份。当用户登录成功之后,会通过一 定的算法,将用户信息、时间戳等进行加密,加密完成后,通过响应头带回前端存储在Cookie中,所以说本质还是存储在Cookie里,当重新打开浏览器的时候,如果再次访问相同网站,浏览器会自动将Cookie中的信息发送给目标服务器,服务器对Cookie中的信息进行校验分析,进而确定出用户的身份,Cookie 中所保存的用户信息也是有时效的,这是可以在程序中限制的,最常见的就是七天免登录。 但是,就算是加密了,这种方式还是会存在安全隐患。这种方式使用便利,但是要牺牲一定的安全性,不过RememberMe会有自己的方式减少自身带来的安全风险。
1.2 RememberMe的用法
还是创建一个Spring Boot工程,引入Spring Security依赖。随后再添加一个HelloController用来测试,代码如下:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("jack")
.password("1234")
.roles("admin");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.rememberMe()
.key("jack")
.and()
.csrf().disable();
}
}
再次启动项目访问/hello接口,我们就会发现出现了RememberMe勾选框:
这里我们主要是调用了HttpSecurity 中的 rememberMe 方法,这样就开启了“记住我”这个功能,然后配置了一个key,该方法其实就是将RememberMeAuthenticationFilter过滤器添加到过滤器链中。这时,登陆的时候勾选上RememberMe,登录成功之后,就可以访问/hello接口了。此时,关闭浏览器再重新打开,就可以无需登录,直接进行/hello接口的访问;那么,就算重启项目重,再去访问hello接口,会发现此时仍然不需要登录。
为了测试,我将用户名改成了jacks,打开控制台,点击登录就会看到请求的接口,可以看到表单数据提交的时候多了一个请求参数remember-me,也就是说,remember-me参数就是用来告诉Spring Security服务是否需要开启RememberMe功能。那么,换成了自定义登录页面,是否开启RememberMe的默认参数就是remember-me。
再来看,当请求成功后,在响应头中多出了一个Set-Cookie,在响应头中给出了一个remember-me字符串。以后所有请求的请求头Cookie字段,都会自动携带上这个令牌,服务端利用该令牌可以校验用户身份是否合法。大致的流程就是这样,但是这种方式安全隐患很大,一旦remember-me令牌泄漏,某些人就可以拿着这个令牌去为所欲为。所以,RememberMe功能还有一些安全措施,比如持久化令牌和二次校验等,可以降低该问题带来的风险,但是不能完全防范。