Spring Security 6.x 系列(6)—— 显式设置和修改登录态信息

一、前言

此篇是对上篇 Spring Security 6.x 系列(5)—— Servlet 认证体系结构介绍 中4.9章节显式调用SecurityContextRepository#saveContext进行详解分析。

二、设置和修改登录态

2.1 登录态存储形式

使用Spring Security框架,认证成功后的用户信息会放在Authentication对象的Principal中,
Authentication对象又会被放入SecurityContext中,而SecurityContext 存在这2个地方:

  • SecurityContextHolderStrategy :线程级别的SecurityContext持有策略。有全局共享、线程继承、线程隔离等几种获取上下文的方式(上文有过介绍)。

  • SecurityContextRepository:持久化SecurityContext ,默认存入HttpServletRequestHttpSession

在代码中,我们要获取用户登录信息,可以通过SecurityContextHolder.getContext().getAuthentication()的方式获取,这种方式是从SecurityContextHolderStrategy获取用户数据。而SecurityContextHolderStrategy初始化数据又是来自SecurityContextRepository,相关逻辑是在SecurityContextHolderFilter类里。

SecurityContextHolderFilter#doFilter源码如下:

在这里插入图片描述
查看securityContextRepository如下:

在这里插入图片描述

设想一种场景,在用户登录后,编辑了用户信息,这时要同步刷新SecurityContext里的用户信息。我们要如何更新这两个处的用户数据呢?

2.2 更新SecurityContextHolderStrategy中的用户信息

要更新SecurityContextHolderStrategy非常简单,因为它保存在内存里,只要通过SecurityContextHolder.getContext().getAuthentication() 获取认证信息后,直接设置对应的属性,内存中属性值发生变化,后续处理逻辑就能读到最新值。

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
MyUser myUser = (MyUser) authentication.getPrincipal();
myUser.setNickname("新的昵称");

2.3 更新SecurityContextRepository中的用户信息

2.3.1 了解SecurityContextRepository接口

SecurityContextRepository是一个接口,源码如下:

public interface SecurityContextRepository {/** @deprecated */@DeprecatedSecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder);default DeferredSecurityContext loadDeferredContext(HttpServletRequest request) {Supplier<SecurityContext> supplier = () -> {return this.loadContext(new HttpRequestResponseHolder(request, (HttpServletResponse)null));};return new SupplierDeferredSecurityContext(SingletonSupplier.of(supplier), SecurityContextHolder.getContextHolderStrategy());}void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response);boolean containsContext(HttpServletRequest request);
}

SecurityContextRepository接口有以下几个实现类:

  • NullSecurityContextRepository:什么都不做,也就是不会存储,每次请求都需要重新认证
  • HttpSessionSecurityContextRepository:将SecurityContext保存在Session中,获取的时候,从Session中查询
  • RequestAttributeSecurityContextRepository:将SecurityContext保存在请求对象HttpServletRequest
  • DelegatingSecurityContextRepository:委派代理存储,内部维护多个SecurityContextRepository,实现同时支持多种方式存储SecurityContext

2.3.2 无法直接获取SecurityContextRepository对象

要知道怎么更新SecurityContextRepository ,我们先看其他地方是怎么调用它。往SecurityContextRepository写数据是在用户认证成功之后,调用AbstractAuthenticationProcessingFilter#successfulAuthentication() 方法,执行认证成功的后续逻辑时。

在这里插入图片描述
在这里插入图片描述

这里的this.securityContextRepository是通过setter方法传进来的,并且发现Spring Security没有把SecurityContextRepository注册到Spring容器,而且Spring Security其他持有SecurityContextRepository对象的类都没有暴露SecurityContextRepository的获取方法。也就是说,我们无法从Spring Security拿到默认的SecurityContextRepository对象。

debug发现this.securityContextRepository属性指向了 DelegatingSecurityContextRepository,这是委派代理存储,代理的对象是 RequestAttributeSecurityContextRepositoryHttpSessionSecurityContextRepository,所以在默认的情况下,用户登录成功之后,在这里就把登录用户数据分别存入到HttpSessionSecurityContextRepositoryRequestAttributeSecurityContextRepository中。

在这里插入图片描述

部分DelegatingSecurityContextRepository源码如下:

在这里插入图片描述
在这里插入图片描述

2.3.3 手动设置SecurityContextRepository对象

为了顺利拿到SecurityContextRepository对象,我们可以手动往Spring容器注册一个SecurityContextRepository对象,然后把它塞到Spring Security里。通过这种方式,我们能从Spring容器拿到SecurityContextRepository 对象,然后随时刷新SecurityContext

具体实现代码如下:

@Bean
public SecurityContextRepository securityContextRepository() {return new DelegatingSecurityContextRepository(new RequestAttributeSecurityContextRepository(), new HttpSessionSecurityContextRepository());
}@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity, SecurityContextRepository securityContextRepository) throws Exception {httpSecurity.securityContext((context) -> context.securityContextRepository(securityContextRepository()));
}

这里DelegatingSecurityContextRepositorySpring Security中的SecurityContextRepository默认实现,我们原封不动保留下来。

2.3.4 更新登录态

在更新完SecurityContextHolderStrategy 对象之后,我们显式把SecurityContext重新保存到SecurityContextRepository

// 更新SecurityContextHolderStrategy
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
MyUser myUser = (MyUser) authentication.getPrincipal();
myUser.setNickname("新的昵称");// 更新SecurityContextRepository
securityContextRepository.saveContext(SecurityContextHolder.getContext(), request, response);

三、总结

通过显式更新SecurityContextHolderStrategySecurityContextRepository ,我们就能完整更新SecurityContext 中的用户信息。如果项目中引入了Spring SessionSpring Session维护的登录态也会同步更新。

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

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

相关文章

使用 ChatGPT 创建 Makefile 构建系统:从 Docker 开始

使用 Docker 搭配 ChatGPT 创建 Makefile 构建系统 Makefile 构建系统是嵌入式软件团队实现其开发流程现代化的基础。构建系统不仅允许开发人员选择各种构建目标&#xff0c;还可以将这些构建集成到持续集成/持续部署 (CI/CD) 流程中。使用诸如 ChatGPT 这样的人工智能 (AI) 工…

深度剖析API接口测试工具的企业价值

随着企业软件开发的日益复杂和互联网应用的普及&#xff0c;API接口成为不同软件系统之间信息传递的桥梁。在这一背景下&#xff0c;API接口测试工具的应用变得愈加重要&#xff0c;对企业的发展和软件质量起到了关键性的作用。本文将深入探讨API接口测试工具在企业中的重要性&…

leetcode:2133. 检查是否每一行每一列都包含全部整数(python3解法)

难度&#xff1a;简单 对一个大小为 n x n 的矩阵而言&#xff0c;如果其每一行和每一列都包含从 1 到 n 的 全部 整数&#xff08;含 1 和 n&#xff09;&#xff0c;则认为该矩阵是一个 有效 矩阵。 给你一个大小为 n x n 的整数矩阵 matrix &#xff0c;请你判断矩阵是否为一…

matlab配置

matlab配置 windowslinux挂载安装MATLAB windows 按照这里一步步配置就行( 移动硬盘中软件备份中自取) linux linux配置步骤 挂载 sudo mount -t auto -o loop /media/oyk/Elements/ubuntu/MATLAB/R2017a_glnxa64_dvd1.iso ./matlab/安装MATLAB 挂载完成后&#xff0c;先…

SpringCloudAlibaba之Nacos的持久化和高可用——详细讲解

目录 一、Nacos持久化 1.持久化说明 2.安装mysql数据库5.6.5以上版本(略) 3.修改配置文件 二、nacos高可用 1.集群说明 2.nacos集群架构图 2.集群搭建注意事项 3.集群规划 4.搭建nacos集群 5.安装Nginx 6.配置nginx conf配置文件 7.启动nginx进行测试即可 一、Nacos持久…

laravel8中常用路由使用(笔记四)

目录 1、框架路由目录统一放该目录 2、基本路由,路由都调用Route方法 3、控制器使用路由 4、路由参数 5、路由组 6、命名路由 7、命令查看当前路由列表 8、路由缓存 在Laravel 8中&#xff0c;路由定义了应用程序中接受请求的方式。它们定义了URL和相应的控制器方法之间的…

13、LCD1602调试工具

LCD1602调试工具 使用LCD1602液晶屏作为调试窗口&#xff0c;提供类似Printf函数的功能&#xff0c;可实时观察单片机内部数据的变化情况&#xff0c;便于调试和演示。 main.c #include <REGX52.H> #include "LCD1602.h" #include "Delay.h"//存储…

【开源】基于JAVA的海南旅游景点推荐系统

项目编号&#xff1a; S 023 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S023&#xff0c;文末获取源码。} 项目编号&#xff1a;S023&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用户端2.2 管理员端 三、系统展示四…

前端开发学习 (三) 列表功能

一、列表功能 1、列表功能 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv"X-UA-Compa…

锂电行业废水及母液除铊解决方案,除铊树脂技术

锂电池原材料和生产设备的制造、电池回收和处理等&#xff0c;产业的发展会带来铊排放问题。除了锂电池生产过 程中存在的铊污染外&#xff0c;企业的生活污水或者初期雨水也含有铊&#xff0c;因为铊是一种广泛存在于自然环境中的 元素&#xff0c;存在于饮用水、土壤和食物中…

高效视频剪辑:按指定时长批量分割视频,释放无尽创意

随着数字媒体技术的不断发展&#xff0c;视频剪辑已经成为日常生活中不可或缺的一部分。无论是制作电影、电视剧&#xff0c;还是创意生活短视频&#xff0c;视频剪辑都扮演着重要的角色。然而&#xff0c;对于许多非专业人士来说&#xff0c;视频剪辑可能是一项复杂而耗时的任…

27.0/多态/对象向上转型/向下转型/抽象类/抽象方法。

目录 27.1为什么使用多态? 27.1.2什么是多态 27.1.3对象多态 27.1.4多态的使用前提 27.2 向上转型 27.3向下转型 (面试题) 27.4抽象类和抽象方法 特点(面试题): 27.1为什么使用多态? 需求1&#xff1a;动物园让我们实现一个功能&#xff1a; 创建一个狗类 &#xff0c;狗…

Leetcode—739.每日温度【中等】

2023每日刷题&#xff08;四十二&#xff09; Leetcode—739.每日温度 单调栈实现思想 从右到左实现代码 class Solution { public:vector<int> dailyTemperatures(vector<int>& temperatures) {int n temperatures.size();stack<int> st;vector<i…

ensp 启动设备时报40错误,然后一直没有去管,再次进去就好了,我知道是配置虚拟机的时候修改了一些设置:

第一个阶段&#xff1a; 那时我是重置电脑之后就安装了ensp所以没有出现什么问题&#xff0c;&#xff08;那时没有导入ce6800和12800还有防火墙6000&#xff09; 第二个阶段&#xff1a; 因为有华为相关的实验要做&#xff0c;所以心血来潮打开了ensp&#xff08;路由器之前…

Digicert OV 代码签名介绍

Digicert OV 代码签名证书是一种数字证书&#xff0c;用于对软件代码进行数字签名。数字签名是一种验证软件来源和完整性的技术&#xff0c;通过使用私有密钥对代码进行签名&#xff0c;并在签名后使用公共密钥验证签名。 可基于更多平台&#xff0c;最大限度地提高分发量和收…

03、K-means聚类实现步骤与基于K-means聚类的图像压缩(2)

03、K-means聚类实现步骤与基于K-means聚类的图像压缩&#xff08;2&#xff09; 工程下载&#xff1a;K-means聚类实现步骤与基于K-means聚类的图像压缩 其他&#xff1a; 03、K-means聚类实现步骤与基于K-means聚类的图像压缩&#xff08;1&#xff09; 03、K-means聚类实现…

Linux 命令ln

1什么是链接 ln在Linux中 ln 命令的功能是为某一个文件在另外一个位置建立一个同步的链接&#xff0c;当我们需要在不同的目录&#xff0c;用到相同的文件时&#xff0c;我们不需要在每一个需要的目录下都放一个必须相同的文件&#xff0c;我们只要在某个固定的目录&#xff0…

SpringBoot监控Redis事件通知

Redis的事件通知 Redis事件通过 Redis 的订阅与发布功能&#xff08;pub/sub&#xff09;来进行分发&#xff0c; 因此所有支持订阅与发布功能的客户端都可以在无须做任何修改的情况下&#xff0c; 使用键空间通知功能。 因为 Redis 目前的订阅与发布功能采取的是发送即忘&am…

Python爬虫入门课: 如何实现数据抓取 <文字 图片 音频 视频 文档..>

嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 环境使用: Python 3.10 解释器 Pycharm 编辑器 模块使用: requests re csv pandas 爬虫实现第一步: 一. 抓包分析 找到对应数据链接地址 套用代码: 修改…

Mybatis 源码搭建

文章目录 源码下载测试模块搭建学习博客 源码下载 首先下载mybatis-parent的源码&#xff1a;gitee地址 > https://gitee.com/callback_lab/mybatis-parent.git 然后下载mybatis的源码&#xff1a;gitee地址 > https://gitee.com/callback_lab/mybatis-src.git 带中文…