文档章节

精通Spring Boot—— 第二十篇:Spring Security记住我功能

liululee
 liululee
发布于 02/07 16:59
字数 1384
阅读 98
收藏 9

引言

本章的代码实现是在上一篇教程:精通Spring Boot——第十九篇:Spring Security 整合验证码登录基础上,如果感觉本篇跳跃幅度较大,可先阅读上一篇,或访问我的github.com(文末会附上地址),下载源码阅读。

1.基本原理介绍

Spring Security记住我功能的基本原理: 首先当我们的浏览器发送请求到UsernamePasswordAuthenticationFilter时,如果认证成功的话,会调用一个RememberMeService服务, 在RememberMeService中,存在一个TokenRepository,它会将token写入到浏览器的cookie中,并将token同时写入到数据库。当用户在下一次重新登录时,服务请求会经过RememberMeAuthentionFilter,这个filter会读取浏览器Cookie中的token,然后再传递给RememberMeService, RememberMeService再去数据库中查询该token是否有效,若该token有效,则会取出对应的用户名,再去调用UserDetailsService获取用户信息,再将用户信息放入SecurityContext里面。

---图片来源网络

RememberMeAuthentionFilter在Spring Security过滤器链中处于AuthenticationFileter中的最后,当其他验证方式无法验证用户信息时,才会调用RememberMeAuthentionFilter类来验证用户信息。

---图片来源网络

2.如何实现

要实现记住我功能,在Spring Security中操作比较简单,只需要实例化PersistentTokenRepository,然后在配置中增加rememberMe配置就行,具体代码实现如下:

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();
    }
}

在页面中,新增记住我

  <span><input name="rememberMe" type="checkbox" th:value="true">记住我</span>

3.测试

经过上面的步骤,我们基本上已经完成了如何添加记住我功能,接下来我们在页面上输入用户名和密码,并同时点击记住我。登录成功后,会跳转至welcome.html页。然后重启系统,清空服务器session, 再次去访问welcome.html,看看能否直接访问。 点击登录,已经成功跳转到welcome.html,重启清空session,直接在地址输入http:localhost:8080/welcome.html 直接能够访问,说明在请求在经过Spring Security过滤器链时,读取了cookies中的token,并通过token去查找了用户的信息,再通过userDetailsService进行了登录。

4.记住我源码分析

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的验证实现,大概可以得出这样的结论

5.总结

这篇的内容主要目的是为系统增加‘记住我’功能,相对比较简单,代码的编写量也比较少。在本篇我们也分析了一下Spring Security中实现这个功能的源码,需要实现的主要是PersistentTokenRepository,并在配置中增加RememberMe的配置。 本篇的源代码可在我的github.com中找到,欢迎大家star 精通Spring Boot系列和follow我本人,也可以加我本人微信探讨技术,感谢您观看此文,谢谢!

© 著作权归作者所有

liululee
粉丝 127
博文 66
码字总数 90743
作品 0
杭州
程序员
私信 提问
加载中

评论(2)

liululee
liululee 博主

引用来自“Java成长之路”的评论

看完了,没有学会,写的不够详细,我是自学主义者,有点笨
欢迎加我微信交流 : 13738718661
Java成长之路
Java成长之路
看完了,没有学会,写的不够详细,我是自学主义者,有点笨
Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密...

小致Daddy
2018/08/03
19.5K
1
springboot微服务系列教程

微服务系列教程 Spring Boot 2是微服务的基础,在2018年3月初,Spring Boot 正式宣布进入2.0时代。下面一起来步入Spring Boot 2时代,领略Spring Boot 2带来的开发乐趣吧! 本系统源代码地址...

鱼煎
01/13
322
0
《 Kotlin + Spring Boot : K2EE 服务端开发实战 》

《 Kotlin + Spring Boot : K2EE 服务端开发实战 》 第一篇 Spring Boot 基础 第1章 Spring Boot 与 Kotlin 的极简理念 第2章 Spring Boot + Kotlin 快速开始 Hello World 第3章 Spring Boo...

程序员诗人
2017/11/02
0
0
Spring Boot学习笔记

多模块开发 [SpringBoot学习]-IDEA创建Gradle多Module结构的SpringBoot项目 RabbitMQ RabbitMQ 安装 linux安装RabbitMQ详细教程 Ubuntu 16.04 RabbitMq 安装与运行(安装篇) ubantu安装...

OSC_fly
2018/07/26
0
0
高手问答第 186 期 —— 拥抱 Spring Cloud 拥抱微服务生态

OSCHINA 本期高手问答(1 月 17 日 - 1 月 23 日)我们请来了杨恩雄@杨大仙的程序空间 为大家解答关于 Spring Cloud 以及微服务架构方面的问题。 杨恩雄,从事 Java EE 企业应用开发十多年,曾...

局长
2018/01/16
6.7K
99

没有更多内容

加载失败,请刷新页面

加载更多

最简单的获取相机拍照的图片

  import android.content.Intent;import android.graphics.Bitmap;import android.os.Bundle;import android.os.Environment;import android.provider.MediaStore;import andr......

MrLins
54分钟前
4
0
说好不哭!数据可视化深度干货,前端开发下一个涨薪点在这里~

随着互联网在各行各业的影响不断深入,数据规模越来越大,各企业也越来越重视数据的价值。作为一家专业的数据智能公司,个推从消息推送服务起家,经过多年的持续耕耘,积累沉淀了海量数据,在...

个推
55分钟前
7
0
第三方支付-返回与回调注意事项

不管是支付宝,微信,还是其它第三方支付,第四方支付,支付机构服务商只要涉及到钱的交易都要进行如下校验,全部成功了才视为成功订单 1.http请求是否成功 2.校验商户号 3.校验订单号及状态...

Shingfi
58分钟前
4
0
简述Java内存分配和回收策略以及Minor GC 和 Major GC(Full GC)

内存分配: 1. 栈区:栈可分为Java虚拟机和本地方法栈 2. 堆区:堆被所有线程共享,在虚拟机启动时创建,是唯一的目的是存放对象实例,是gc的主要区域。通常可分为两个区块年轻代和年老代。更...

DustinChan
今天
6
0
Excel插入批注:可在批注插入文字、形状、图片

1.批注一直显示:审阅选项卡-------->勾选显示批注选项: 2.插入批注快捷键:Shift+F2 组合键 3.在批注中插入图片:鼠标右键点击批注框的小圆点【重点不可以在批注文本框内点击】----->调出批...

东方墨天
今天
6
1

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部