本章的代码实现是在上一篇教程:精通Spring Boot——第十九篇:Spring Security 整合验证码登陆基础上,若是感受本篇跳跃幅度较大,可先阅读上一篇,或访问个人github.com(文末会附上地址),下载源码阅读。html
Spring Security记住我功能的基本原理: 首先当咱们的浏览器发送请求到UsernamePasswordAuthenticationFilter时,若是认证成功的话,会调用一个RememberMeService服务, 在RememberMeService中,存在一个TokenRepository,它会将token写入到浏览器的cookie中,并将token同时写入到数据库。当用户在下一次从新登陆时,服务请求会通过RememberMeAuthentionFilter,这个filter会读取浏览器Cookie中的token,而后再传递给RememberMeService, RememberMeService再去数据库中查询该token是否有效,若该token有效,则会取出对应的用户名,再去调用UserDetailsService获取用户信息,再将用户信息放入SecurityContext里面。 java
---图片来源网络git
RememberMeAuthentionFilter在Spring Security过滤器链中处于AuthenticationFileter中的最后,当其余验证方式没法验证用户信息时,才会调用RememberMeAuthentionFilter类来验证用户信息。 github
---图片来源网络web
要实现记住我功能,在Spring Security中操做比较简单,只须要实例化PersistentTokenRepository,而后在配置中增长rememberMe配置就行,具体代码实现以下:spring
import com.linking.springsecurityremeberme.filter.CaptchaFilter; import com.linking.springsecurityremeberme.handler.MyFailureHandler; import com.linking.springsecurityremeberme.service.impl.UserDetailsServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl; import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository; import javax.sql.DataSource; /** * @author developlee * @since 2019/1/18 15:30 */ @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsServiceImpl userDetailsService; @Autowired private DataSource dataSource; @Bean public PersistentTokenRepository tokenRepository() { JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl(); jdbcTokenRepository.setDataSource(dataSource); // 设置为true,则项目启动时,会在对应数据源中自动建表token表 jdbcTokenRepository.setCreateTableOnStartup(false); return jdbcTokenRepository; } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Autowired private AppConfig appConfig; @Override protected void configure(HttpSecurity http) throws Exception { http.formLogin().loginPage("/sign_in").loginProcessingUrl(appConfig.getLoginUri()) .defaultSuccessUrl("/welcome").permitAll() .failureHandler(new MyFailureHandler()) .and().authorizeRequests().antMatchers("/code/image").permitAll() .and().addFilterBefore(new CaptchaFilter(appConfig, new MyFailureHandler()), UsernamePasswordAuthenticationFilter.class) .logout().logoutUrl("/auth/logout").clearAuthentication(true) .and().rememberMe().tokenRepository(tokenRepository())//设置tokenRepository .alwaysRemember(true) // 老是记住,会刷新过时时间 .tokenValiditySeconds(300)// 设置过时时间为5分钟 .userDetailsService(userDetailsService) // 设置userDetailsService,用来获取username .and().authorizeRequests().anyRequest().authenticated(); } }
在页面中,新增记住我sql
<span><input name="rememberMe" type="checkbox" th:value="true">记住我</span>
通过上面的步骤,咱们基本上已经完成了如何添加记住我功能,接下来咱们在页面上输入用户名和密码,并同时点击记住我。登陆成功后,会跳转至welcome.html页。而后重启系统,清空服务器session, 再次去访问welcome.html,看看可否直接访问。 点击登陆,已经成功跳转到welcome.html,重启清空session,直接在地址输入http:localhost:8080/welcome.html 直接可以访问,说明在请求在通过Spring Security过滤器链时,读取了cookies中的token,并经过token去查找了用户的信息,再经过userDetailsService进行了登陆。数据库
OK,咱们先从第一步登陆操做开始提及,第一次登陆时,必然会通过UsernamePasswordAuthenticationFilter,因此把断点设置在该类中 而后接着代码走走走,下一步来到successfulAuthentication这个方法,也就是登陆成功后的处理方法,能够看到这里rememberService会将登陆成功的用户信息保存
浏览器
OK,再接着走,看下这个rememberService.onLoginSuccess具体实现 能够看到,这个方法,会将一条token记录插入到数据库中,并写入到Cookie。到这里为止,登陆操做基本已经完成。 接下来从新启动下服务,并直接访问welcome.html,看看代码的执行顺序如何。断点要打在RememberMeService中的autoLogin方法。 看下实现,首先是判断cookie是否为null和为空,接着往下走,来到decodeCookie解析cookie,而后经过processAutoLoginCookie这个方法,去数据库中经过cookieToken查询用户信息,接下来再对用户信息进行校验(用户更换了密码之类的状况),check成功后,再执行登陆操做,写入用户信息到SecurityContext中。
服务器
如下是processAutoLoginCookie方法的具体实现。
在Spring Security中实现记住我功能有两种实现,一种是上面介绍的PersistentTokenBasedRememberMeService,一种是TokenBasedRememberService。 这两种的区别主要在于什么呢? 它们是AbstractRememberMeServices.onLoginSuccess方法的不一样实现。 上面介绍的PersistentTokenBasedRememberMeService,是生成token的key,expireTime等信息保存在数据库中的,而TokenBasedRememberService则是将key,expireTime等信息保存在客户端(浏览器)中的,验证方式也全部不一样。 看下TokenBasedRememberService中对token的验证明现,大概能够得出这样的结论
这篇的内容主要目的是为系统增长‘记住我’功能,相对比较简单,代码的编写量也比较少。在本篇咱们也分析了一下Spring Security中实现这个功能的源码,须要实现的主要是PersistentTokenRepository,并在配置中增长RememberMe的配置。 本篇的源代码可在个人github.com中找到,欢迎你们star 精通Spring Boot系列和follow我本人,也能够加我本人微信探讨技术,感谢您观看此文,谢谢!