【1】基于会话技术的实现
也就是基于Cookie的实现。
① 登录页面
这里name="remember-me"表示“记住我”的复选框,默认key是remember-me
。
<form action="/user/login" method="post">
<input type="text" name="username" />
<input type="text" name="password" />
<input type="checkbox" name="remember-me" />
<input type="submit" />
</form>
② 配置类开启记住我功能
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(password());
}
@Bean
PasswordEncoder password() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().accessDeniedPage("/unauth.html");
http.formLogin()
.loginPage("/login.html") //登录页面
.loginProcessingUrl("/user/login") // 处理登录的请求
.defaultSuccessUrl("/test/index",true)// 登录成功后跳转路径
.permitAll();
http.authorizeRequests()
.antMatchers("/static/**","/images/**","/css/**","/js/**")//可以直接放行
.permitAll()
.antMatchers("/findAll").hasAuthority("admin") // 用户访问findAll 必须有 admin 权限
.antMatchers("/find").hasAnyAuthority("admin","sale") // 用户访问 find ,拥有admin或者sale之一即可
.antMatchers("/sale/**").hasRole("sale") // 需要用户具有sale角色
.antMatchers("/product/**").hasAnyRole("admin","product") //用户具有admin或者product角色之一即可
.anyRequest().authenticated();//其他请求都需要认证
http.csrf().disable();
//开启记住我
http.rememberMe();
}
}
如下所示,提交表单时请求参数会带上remember-me: on
:
提交表单后响应头会设置cookie-remember-me,默认是14天有效期。其值加密规则如下所示:
username + ":" + expiryTime + ":"
+ Md5Hex(username + ":" + expiryTime + ":" + password + ":" + key)
.
此时关闭浏览器再重新打开,可直接访问受保护的请求(请求头的Cookie会带上remember-me)。
其本质就是根据某种规则生成一个加密串(串中有用户名和密码)设置为cookie,再次请求时带上该cookie。在autoLogin方法中会解密该cookie,然后根据解密中的用户信息与数据库的数据进行对比来实现自动登录。
原理部分可以查阅一下RememberMeConfigurer、TokenBasedRememberMeServices与AbstractRememberMeServices三个类。
这种方式无疑是不安全的,将用户信息通过某种加密规则生成字符串保存到浏览器是有几率被逆向的。故而spring官方推荐使用基于数据库的实现如PersistentTokenBasedRememberMeServices。