SpringSecurity5|12.实现RememberMe 及 实现原理分析

news2024/11/19 19:34:19

security/day08

这个功能大家还熟悉么?我们在登录网站的时候,除了让你输入用户名和密码,还会有个勾选框:
记住我!!!不是让大家记住我哈。

在这里插入图片描述

值得一提的是,Spring Security 也提供了这个功能,我们今天就来体验一把。

代码实战

其实想要开启rememberMe功能,其实很简单,只需要简单的修改下配置即可:

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests().anyRequest().authenticated()
                .and()
                .formLogin()
                .permitAll()
                .and()
                .rememberMe()
                .and()
                .csrf().disable();
        return http.build();
    }

实现思路

  • 当用户登录网站后,并且勾选rememberMe
  • 服务端认证通过,则把用户信息进行算法加密,加密完成后,通过cookie,让浏览器把cookie保存在本地
  • 当浏览器关闭后重新打开网站,浏览器会把cookie带给服务端
  • 服务端校验cookie确定用户身份,进而自动登录

源码分析

首先我们找切入点,我们前面讲过当引入一个新功能的时候,必定会引入一个configurer,rememberMe 也不例外:点击.rememberMe()进入源码
在这里插入图片描述

看到了RememberMeConfigurer,我们点进去看下主要是看init和configure方法

init

	public void init(H http) throws Exception {
		validateInput();
		String key = getKey();
		RememberMeServices rememberMeServices = getRememberMeServices(http, key);
		http.setSharedObject(RememberMeServices.class, rememberMeServices);
		LogoutConfigurer<H> logoutConfigurer = http.getConfigurer(LogoutConfigurer.class);
		if (logoutConfigurer != null && this.logoutHandler != null) {
			logoutConfigurer.addLogoutHandler(this.logoutHandler);
		}
		RememberMeAuthenticationProvider authenticationProvider = new RememberMeAuthenticationProvider(key);
		authenticationProvider = postProcess(authenticationProvider);
		http.authenticationProvider(authenticationProvider);
		initDefaultLoginFilter(http);
	}
  • getKey() 这个就是我们刚开始设置的key,如果不配置,每次系统都会重启,导致需要重新登录
  • getRememberMeServices() 用来实现自动登录、处理登录成功和登录失败的逻辑,主要有两个继承
    • PersistentTokenBasedRememberMeServices 持久化令牌到数据库
    • TokenBasedRememberMeServices
  • http.authenticationProvider(authenticationProvider);创建一个认证器放到providerList里面
  • initDefaultLoginFilter(http); 在自定生成登录页面加上rememberMe 选框

configure

	public void configure(H http) {
		RememberMeAuthenticationFilter rememberMeFilter = new RememberMeAuthenticationFilter(
				http.getSharedObject(AuthenticationManager.class), this.rememberMeServices);
		if (this.authenticationSuccessHandler != null) {
			rememberMeFilter.setAuthenticationSuccessHandler(this.authenticationSuccessHandler);
		}
		rememberMeFilter = postProcess(rememberMeFilter);
		http.addFilter(rememberMeFilter);
	}
  • 创建了一个过滤器:RememberMeAuthenticationFilter
  • postProcess(rememberMeFilter); 注入IOC容器
  • 在http中加入rememberMe过滤器

看完了RememberMeConfigurer的两个核心方法之后,我们现在知道容器中已经有了RememberMeAuthenticationFilter和RememberMeAuthenticationProvider
现在分别来看下

RememberMeAuthenticationFilter

private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		Authentication rememberMeAuth = this.rememberMeServices.autoLogin(request, response);
		if (rememberMeAuth != null) {
			// Attempt authenticaton via AuthenticationManager
			try {
				rememberMeAuth = this.authenticationManager.authenticate(rememberMeAuth);
				// Store to SecurityContextHolder
				SecurityContext context = SecurityContextHolder.createEmptyContext();
				context.setAuthentication(rememberMeAuth);
				SecurityContextHolder.setContext(context);
				onSuccessfulAuthentication(request, response, rememberMeAuth);
			   this.securityContextRepository.saveContext(context, request, response);
				if (this.successHandler != null) {
					this.successHandler.onAuthenticationSuccess(request, response, rememberMeAuth);
					return;
				}
			}
			catch (AuthenticationException ex) {
				this.rememberMeServices.loginFail(request, response);
				onUnsuccessfulAuthentication(request, response, ex);
			}
		}
		chain.doFilter(request, response);
	}
  • 调用autoLogin方法
    • 从cookie提取用户身份,在调用loadUserByUsername获取用户详细信息
    • 校验用户身份是否合法(根据不同的令牌存储方式进行不同校验)
    • 如果校验通过,则返回Authentication(RememberMeAuthenticationToken)
  • authenticate
    • 如果autoLogin成功,则和前面普通登录一样进行认证
    • 因为这里生成的是RememberMeAuthenticationToken,则最终会被RememberMeAuthenticationProvider处理
  • 如果认证返回则进行对应的响应处理

RememberMeAuthenticationProvider

	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		if (!supports(authentication.getClass())) {
			return null;
		}
		if (this.key.hashCode() != ((RememberMeAuthenticationToken) authentication).getKeyHash()) {
			throw new BadCredentialsException(this.messages.getMessage("RememberMeAuthenticationProvider.incorrectKey",
					"The presented RememberMeAuthenticationToken does not contain the expected key"));
		}
		return authentication;
	}

这里的逻辑只做了一步,校验key的hashCode是否一致,如果一致,则校验通过

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1225839.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从0开始学习JavaScript--JavaScript 数字与日期

JavaScript中的数字和日期是处理数值计算和时间相关任务的核心。本文将深入研究JavaScript中数字的表示、常见运算&#xff0c;以及日期对象的创建、格式化等操作&#xff0c;并通过丰富的示例代码&#xff0c;可以更全面地了解和应用这些概念。 JavaScript数字基础 JavaScri…

多线程Thread(初阶一:认识线程)

目录 一、引用线程的原因 二、线程的概念 三、进程和线程的区别 四、多线程编程 一、引用线程的原因 多任务操作系统&#xff0c;希望系统能同时运行多个任务。所以会涉及到进程&#xff0c;需要对进程进行管理、调度等。 而单任务操作系统&#xff0c;就完全不涉及到进程…

供应链|顶刊MSOM论文解读:服务竞争下的库存共享

问题背景 在汽车、玩具等行业中&#xff0c;零售商之间的库存共享变得十分常见。库存共享可以解决由需求不确定导致的库存错配问题。如果零售商之间同意共享库存&#xff0c;那么当需求较少、自身库存过剩时&#xff0c;可以将过剩库存卖给其他零售商&#xff1b;反之&#xf…

从0开始学习JavaScript--JavaScript 字符串与文本内容使用

JavaScript中的字符串和文本内容处理是前端开发中的核心技能之一。本文将深入研究字符串的创建、操作&#xff0c;以及文本内容的获取、修改等操作&#xff0c;并通过丰富的示例代码&#xff0c;帮助读者更全面地了解和应用这些概念。 JavaScript 字符串基础 字符串是JavaScr…

Dart 3.2 更新,Flutter Web 的未来越来越明朗

参考原文&#xff1a;https://medium.com/dartlang/dart-3-2-c8de8fe1b91f 本次跟随 Flutter 3.16 发布 的 Dart 3.2 &#xff0c;包含有&#xff1a;私有 final 字段的非空改进、新的 interop 改进、对 DevTools 中的扩展支持、以及对 Web 路线图的更新&#xff0c;包括对 Was…

LCD1602显示自定义字符

代码&#xff1a; #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27, 16, 2); //根据lcd1602的地址修改0x27. dht DHT; byte degree[8] {B00100, B01010, B10001, B10101, B10101, B01110, B00100,B00100 }; //自定义字符的2进制数据 byte customCh…

Shell脚本:Linux Shell脚本学习指南(第一部分Shell基础)一

你好&#xff0c;欢迎来到「Linux Shell脚本」学习专题&#xff0c;你将享受到免费的 Shell 编程资料&#xff0c;以及很棒的浏览体验。 这套 Shell 脚本学习指南针对初学者编写&#xff0c;它通俗易懂&#xff0c;深入浅出&#xff0c;不仅讲解了基本知识&#xff0c;还深入底…

optee4.0.0 qemu_v8的环境搭建篇(ubuntu20.10)

快速链接: . 👉👉👉 个人博客笔记导读目录(全部) 👈👈👈 付费专栏-付费课程 【购买须知】:【精选】ARMv8/ARMv9架构入门到精通-[目录] 👈👈👈文章目录 前提条件1、拉取代码2、下载工具链3、编译4、运行

Linux系统无法发送组播消息

临时方法&#xff0c;执行系统命令 sudo route add -net 组播ip netmask 255.255.255.255 dev 网卡设备名此方法只是临时生效&#xff0c;机器重启或者拔掉网线后都会失效&#xff0c;需要重新执行该命令才行&#xff0c;下面介绍用就方法&#xff0c;重启和拔网线后依然生效&…

JVM面试必备

目录 JVM三大问题 一、JVM内存区域划分 ​编辑 二、JVM类加载机制 双亲委派模型&#xff08;常考) 类加载的格式&#xff0c;类卸载 三、垃圾回收&#xff08;GC) 具体垃圾回收GC步骤 1.判定对象是否为垃圾 方案1:引用计数 方案2&#xff1a;可达性分析 2.释放对象的…

python——第九天

今日目标&#xff1a; 偏函数 递归 字符串对象 切片 常见排序和查找 偏函数&#xff1a; python中存在一种函数的特殊使用&#xff0c;称为偏函数 如果在调用某个函数时&#xff0c;恰好某一个或者&#xff0c;某一些参数都是一个固定值&#xff08;正好不是默认值&#xff09;…

Windows 11 配置 ssh server 服务

Windows 11 配置 ssh server 服务 1. 安装 ssh server配置 ssh key 登陆设置默认使用 Powershell设置默认访问路径启动 sshd 和设置开机自动启动安装 vim (Powershell 中可以直接使用) 1. 安装 ssh server 打开 “设置” 》 “应用”&#xff0c;然后打开 “可选配置”&#x…

Nacos注册表解读

基本介绍 在 Nacos 中&#xff0c;注册表是其中一个重要的组件&#xff0c;用于管理服务的注册和发现。 注册表是一个存储服务实例信息的数据库&#xff0c;它记录了所有已注册的服务实例的相关信息&#xff0c;包括服务名称、IP 地址、端口号等。 通过注册表&#xff0c;服…

定时获取公网ip并发送邮件提醒

前一段时间路由器刷的老毛子固件“穿透服务”中定时更新阿里DDNS失败了&#xff0c;用了很久第一次遇到。所以需要做个备用的措施用来实时获取公网ip信息 1、基于python实现 开启邮箱的SMTP功能拿到授权码(不是登录密码) #!/usr/bin/python # -*- coding: UTF-8 -*- import …

迭代新品 | 第四代可燃气体监测仪,守护燃气管网安全快人一步

城市地下市政基础设施是城市有序运行的生命线&#xff0c;事关城市安全、健康运行和高质量发展。近年来&#xff0c;我国燃气事故多发、频发。2020、2021、2022 年分别发生燃气事故668、1140 起、802 起&#xff0c;造成92、106、66 人死亡&#xff0c;560、763、487 人受伤。尤…

论文阅读:Auto White-Balance Correction for Mixed-Illuminant Scenes

论文阅读&#xff1a;Auto White-Balance Correction for Mixed-Illuminant Scenes 今天介绍一篇混合光照下的自动白平衡的文章 Abstract 自动白平衡&#xff08;AWB&#xff09;是相机 ISP 通路中比较重要的一个模块&#xff0c;主要用于校正环境光照引起的色偏问题&#x…

实验(二):存储器实验

一、实验内容与目的 实验要求&#xff1a; 利用 CP226 实验仪上的 K16..K23 开关做为 DBUS 的数据&#xff0c;其它开关做为控制信号&#xff0c;实现主存储器 EM 的读写操作&#xff1b;利用 CP226 实验仪上的小键盘将程序输入主存储器 EM&#xff0c;实现程序的自动运行。 实…

【RocketMq系列-01】RocketMq安装和基本概念

RocketMq系列整体栏目 内容链接地址【一】RocketMq安装和基本概念https://zhenghuisheng.blog.csdn.net/article/details/134486709 RocketMq安装和基本概念 一&#xff0c;RocketMq安装和基本概念1&#xff0c;RocketMq基本安装(本地安装)2&#xff0c;Rocketmq的核心概念2.1&…

Redis-布隆过滤器(Bloom Filter)

一、什么是布隆过滤器 布隆过滤器&#xff0c;Bloom Filter是1970年由Bloom提出的&#xff0c;它是由一组哈希&#xff08;Hash&#xff09;函数和一个位阵列组成。布隆过滤器可以用于查询一个元素是否存在于一个集合当中&#xff0c;查询结果为以下二者之一&#xff1a; 这个…

Linux常用命令——bye命令

在线Linux命令查询工具 bye 命令用于中断FTP连线并结束程序。。 补充说明 bye命令在ftp模式下&#xff0c;输入bye即可中断目前的连线作业&#xff0c;并结束ftp的执行。 语法 bye实例 bye在线Linux命令查询工具