security的一个过滤器——SecurityContextPersistenceFilter

spring security 4 filter SecurityContextPersistenceFilter(三) 今天我们讲的filter是SecurityContextPersistenceFilter,通过其名字,就能大概猜出来这个过滤器的作用,就是用来持久化SecurityContext实例用的,也是spring security filter 核心的过滤器之一。 接下去我们将根据其源码分析一下其作用,先看看doFilter这个方法 public void doFilter(Servl... 阅读详情

security的一个过滤器——SecurityContextPersistenceFilter

1、关于security的用户信息获取

a、SecurityContextHolder.getContext().getAuthentication()
b、在 Controller 的方法中,加入 Authentication 参数,调用getPrincipal()方法

问题:异常情况上述两种方式获取用户都为null,即系统获取不到用户信息,报错状态码401,这又是怎么回事呢?
要弄明白这个问题,我们就得明白 Spring Security 中的用户信息到底是在哪里存的?
通过第一种方式security的上下文SecurityContextHolder 中的用户数据,本质上是保存在 ThreadLocal 中,ThreadLocal 的特点是存在它里边的数据,哪个线程存的,哪个线程才能访问到。

这样就带来一个问题,当不同的请求进入到服务端之后,由不同的 thread 去处理,按理说后面的请求就可能无法获取到登录请求的线程存入的数据,例如登录请求在线程 A 中将登录用户信息存入 ThreadLocal,后面的请求来了,在线程 B 中处理,那此时就无法获取到用户的登录信息。

但实际上,正常情况下,我们每次都能够获取到登录用户信息,这又是怎么回事呢?

这我们就要引入 Spring Security 中的 SecurityContextPersistenceFilter 了。security的一系列过滤器链在经过AuthenticationFilter 之前都会先经过 SecurityContextPersistenceFilter这个过滤器。我们来看下源码:

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        if (request.getAttribute(FILTER_APPLIED) != null) 
            chain.doFilter(request, response);
            return;
        }

        final boolean debug = logger.isDebugEnabled();

        request.setAttribute(FILTER_APPLIED, Boolean.TRUE);

        if (forceEagerSessionCreation) {
            HttpSession session = request.getSession();

            if (debug && session.isNew()) {
                logger.debug("Eagerly created session: " + session.getId());
            }
        }

        HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request,
                response);
        //利用HttpSecurityContextRepository从HttpSesion中获取SecurityContext对象
        //如果没有HttpSession,即浏览器第一次访问服务器,还没有产生会话。
        //它会创建一个空的SecurityContext对象
        SecurityContext contextBeforeChainExecution = repo.loadContext(holder);

        try {
            //把SecurityContext放入到SecurityContextHolder中
            SecurityContextHolder.setContext(contextBeforeChainExecution);
            //执行拦截链,这个链会逐层向下执行
            chain.doFilter(holder.getRequest(), holder.getResponse());

        }
        finally { 
            //当拦截器都执行完的时候把当前线程对应的SecurityContext从SecurityContextHolder中取出来
            SecurityContext contextAfterChainExecution = SecurityContextHolder
                    .getContext();
            SecurityContextHolder.clearContext();
            //利用HttpSecurityContextRepository把SecurityContext写入HttpSession
            repo.saveContext(contextAfterChainExecution, holder.getRequest(),
                    holder.getResponse());
            request.removeAttribute(FILTER_APPLIED);

            if (debug) {
                logger.debug("SecurityContextHolder now cleared, as request processing completed");
            }
        }
    }
  • doFilter 方法中,它首先会从 repo 中读取一个 SecurityContext 出来,这里的 repo 实际上就是SecurityContextRepository的实现类HttpSessionSecurityContextRepository,读取 SecurityContext 的操作会进入到readSecurityContextFromSession 方法中,
private SecurityContext readSecurityContextFromSession(HttpSession httpSession) {
        boolean debug = this.logger.isDebugEnabled();
        if (httpSession == null) {
            if (debug) {
                this.logger.debug("No HttpSession currently exists");
            }

            return null;
        } else {
        	//此处 this.springSecurityContextKey的值就是SPRING_SECURITY_CONTEXT
            Object contextFromSession = httpSession.getAttribute(this.springSecurityContextKey);
            if (contextFromSession == null) {
                if (debug) {
                    this.logger.debug("HttpSession returned null object for SPRING_SECURITY_CONTEXT");
                }

                return null;
            } else if (!(contextFromSession instanceof SecurityContext)) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn(this.springSecurityContextKey + " did not contain a SecurityContext but contained: '" + contextFromSession + "'; are you improperly modifying the HttpSession directly (you should always use SecurityContextHolder) or using the HttpSession attribute reserved for this class?");
                }

                return null;
            } else {
                if (debug) {
                    this.logger.debug("Obtained a valid SecurityContext from " + this.springSecurityContextKey + ": '" + contextFromSession + "'");
                }

                return (SecurityContext)contextFromSession;
            }
        }
    }

在这里我们看到了读取的核心方法 Object
contextFromSession =httpSession.getAttribute(springSecurityContextKey);,这里的
springSecurityContext对象的Key值就是SPRING_SECURITY_CONTEXT,读取出来的对象最终会被转为一个 SecurityContext 对象。

  • SecurityContext 是一个接口,它有一个唯一的实现类SecurityContextImpl,这个实现类其实就是用户信息在 session 中保存的 value。

  • 在拿到SecurityContext 之后,通过 SecurityContextHolder.setContext 方法将这个
    SecurityContext 设置到 ThreadLocal 中去,这样,在当前请求中,Spring Security
    的后续操作,我们都可以直接从 SecurityContextHolder 中获取到用户信息了。

  • 接下来,通过 chain.doFilter 让请求继续向下走(这个时候就会进入到 UsernamePasswordAuthenticationFilter 过滤器中了)。

  • 在过滤器链走完之后,数据响应给前端之后,finally 中还有一步收尾操作,这一步很关键。这里从
    SecurityContextHolder 中获取到 SecurityContext,获取到之后,会把
    SecurityContextHolder 清空,然后调用 repo.saveContext 方法将获取到的
    SecurityContext 存入 session 中。

每一个请求到达服务端的时候,首先从 session 中找出来 SecurityContext ,然后设置到 SecurityContextHolder 中去,方便后续使用,当这个请求离开的时候,SecurityContextHolder 会被清空(此处操作很重要,也是security过滤器链控制安全的一种处理技巧),SecurityContext 会被放回 session 中,方便下一个请求来的时候获取。

那么回到最初的问题,什么时候有获取不到当前用户信息:

1、不经过security过滤器,一个新的线程中去执行SecurityContextHolder.getContext().getAuthentication()

2、SecurityContextPersistenceFilter中的session没有用户信息,如果排除第一种方式,按照该过滤器流程,就是上一个请求结束后,没有将上下文放回到session即finally里面的saveContext方法未执行

那么什么时候会出现第二种情况,就要说到security的放行url机制了,一般在WebSecurityConfigurerAdapter配置类里的两个方法:

1、public void configure(WebSecurity web) throws Exception {
		web.ignoring().antMatchers("/xxx","/js/xxx.html");
    }

2、protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
        .antMatchers("/xxx").permitAll()
        .anyRequest().authenticated()
    }

这两个放行的策略区别在于,第一种方式直接没有走security的过滤器,而第二种是经过security过滤器,在过滤器中判断放行

那么有以下结论:

  1. 一般web项目的登陆url放行肯定要走第二种,不经过security过滤器用户信息不会存储到session,后面的请求也无法通过上下文对象获取当前用户信息
  2. 前端静态资源的放行不涉及到用户信息,没必要走security,建议走第一种方式,此为认证,资源无权限特殊情况除外
  3. 额外放行不需要认证的的url,如果采取了第一种方式,那么在当前请求中是无法获取用户信息的,原因就是没有走我们的主角过滤器:SecurityContextPersistenceFilter,要是项目特殊,需要在放行的url里面也获取到用户信息的话,那么可以走第二种配置,有些旧的xml配置(security在mvc项目中未火的主要原因就是xml配置太过繁琐,直至springboot的javaconfig以及自动装配才大放异彩)不支持或是不方便修改,可以手动加一个过滤器模仿SecurityContextPersistenceFilter,将是放行的url提前从session中通过上下文对象SecurityContext的key值SPRING_SECURITY_CONTEXT重新获取下,手动放置SecurityContextHolder中
Spring Security详解(三)认证之核心过滤器 这章主要用来分析Spring Security中的过滤器链包含了哪些关键的过滤器,并且各自的作用是什么。 3 核心过滤器 3.1 概述 Filter顺序 Spring Security的官方文档向我们提供了filter的顺序,无论实际应用中你用到了哪些,整体的顺序是保持不变的: - ChannelProcessingFilter,重定向到其他协议的过滤器。也就是说如果你访问的... 阅读详情

相关推荐

Spring Security认证授权流程

在以上代码的for循环中,第一次拿到的 provider 是一个 Anonymous Authentication Provider。Spring Security会监听这个事件,接收到这个Authentication对象,进而调用 SecurityContextHolder.getContext().setAuthentication(...)方法,将 Authentication Manager返回的 Authentication对象,存储在当前的 Security Context 对象中。

2303_78503642的博客 3925

史上最简单的Spring Security教程(四十):SecurityContextPersistenceFilter详解

SecurityContextPersistenceFilter,为Spring Security框架Filter Chain过滤器链的第一个 Filter,具有不可或缺的作用。 /** * Populates the {@link SecurityContextHolder} with information obtained from the * configured {@link SecurityContextRepository} prior to the request an...

银河架构师的博客 2606

java技术专家 【安全框架第九篇】 SpringSecurity核心过滤器-SecurityContextPersistenceFilter

java技术专家 安全框架【第九篇】SpringSecurity核心过滤器-SecurityContextPersistenceFilter

大壮 1100

SecurityContextPersistenceFilter详解

试想一下,如果我们不使用Spring Security,如果保存用户信息呢,大多数情况下会考虑使用Session对吧?在Spring Security中也是如此,用户在登录过一次之后,后续的访问便是通过sessionId来识别,从而认为用户已经被认证。SecurityContextHolder存放用户信息,认证相关的信息是如何被存放到其中的,便是通过SecurityContextPersistenceFilter。SecurityContextPersistenceFilter的两个主要作用便是请求来临时,

小汤圆 2127

SpringSecurity源码解析--SecurityContextPersistenceFilter

概述 SecurityContextPersistenceFilter有两个主要任务: 在请求到达时处理之前,从SecurityContextRepository中获取安全上下文信息填充到SecurityContextHolder; 在请求处理结束后返回响应时,将SecurityContextHolder中的安全上下文信息保存回SecurityContextRepository,并清空SecurityContextHolder。 通过SecurityContextPersistenceFilter的这种

程序员劝退师的博客 544

一种基于改进YOLOv8并与ORB-SLAM3融合的动态环境密集点云同步定位与建图(SLAM)方法

文章提出了一种基于改进 YOLOv8 与 ORB-SLAM3 融合的动态环境稠密点云 SLAM 方法,通过引入GSConv 卷积模块和VoVGSCSP 特征融合模块优化 YOLOv8 的轻量性,结合实时目标检测与语义分割技术去除动态特征点,显著提升了动态场景下的位姿估计精度。

2401_87345388的博客 1940

【第九篇】SpringSecurity核心过滤器-SecurityContextPersistenceFilter

在SpringSecurity中的jar分为4个,作用分别为。

yqqの博客 447

多模型对抗性审查:用AI辩论提升技术文档质量

在软件工程领域,技术文档是团队协作和项目成功的关键基础。传统的文档评审依赖人工经验,存在盲区和效率瓶颈。通过引入多模型对抗性审查机制,不同大语言模型从各自视角对文档进行批判性分析,模拟现实中的专家评审过程。这种技术方法的核心价值在于利用模型间的思维差异,自动发现单个视角容易忽略的边界情况、逻辑漏洞和隐含假设。在应用场景上,特别适合产品需求文档和技术规格书这类需要多角度审视的复杂文档。adversarial-spec工具通过Claude协调多模型辩论,实现从概念到实现的完整文档质量保障,显著提升文档的完整性和

weixin_42531579的博客 379

spring security 过滤器链分析

文章目录一、spring security 是什么?二、过滤器链讲解 提示:以下是本篇文章正文内容,下面案例可供参考 一、spring security 是什么? spring security 是一种安全框架,一种安全服务。本质是一堆过滤器链。 其主要功能分为俩个主体和授权。 二、过滤器链讲解 过滤器主要有12个 名称 简介 WebAsyncManagerIntegrationFilter 为请求处理过程中可能发生的异步调用准备安全上下文获取途径 SecurityContextPe

weixin_46135502的博客 341

双目视觉实战:用Bouguet算法实现极线校正的完整代码解析

本文详细解析了Bouguet算法在双目视觉极线校正中的完整实现流程与性能调优技巧。通过旋转平分策略和基线对齐,Bouguet方法显著降低图像畸变并提升匹配精度,相比传统Hartley校正法平均重投影误差降低53%。文章涵盖从相机标定到OpenCV实战的全过程,并分享工业级调参策略,帮助开发者实现高精度立体视觉系统。

f9g0h的博客 268

微信小程序-如何根据缩放屏幕大小自适应icon图标更改marker

微信小程序如何根据用户的缩放屏幕来改变marker图标icon的大小,实现icon自适应屏幕缩放的效果

Bartender_VA11的博客 3981

SecurityContextPersistenceFilter是如何做到任何对 SecurityContext 的改变都可以被 copy 到 HttpSession。

首先查看其中的doFilter方法的代码 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { ....... //省略部分代码 H

u013828625的博客 2504

RISC-V CPU设计(三)---多周期CPU的设计与实现

基本情况 本多周期CPU支持RV32I指令集(fence,ecall,ebreak除外),已通过部分指令的测试,如代码有bug,欢迎指出。 模块划分 代码将CPU划分为以下几个模块: 1.控制单元:ControlUnit 用于产生控制信号,是CPU的大脑,指挥中枢。 2.分支决策单元:BranchUnit 用于决定B型指令是否发生跳转 3.立即数单元:ImmUnit 用于从指令中解析出立即数. 4.寄存器堆:RegisterFile RISC-V的32个寄存器,其中x0寄存器恒为0,不可更改。 5.指令存储

qq_40268672的博客 5542

[3] SecurityContextPersistenceFilter

SecurityContextPersistenceFilter 介绍 我们从字面上可以看出这是一个SecurityContext持久化的过滤器,这个也是SecurityContext相关的过滤器。再一次HTTP请求经过该过滤器时,Spring Security会先从SecurityContextRepository的取认证信息,这个接口有2种实现,分别是:1)_NullSecurityCont...

既无风雨也无晴 2万+

分享6款文字语音生成驱动虚拟数字人说话的开源项目

对定性和定量结果的大量实验表明,我们的算法实现了高质量的照片真实感对话头部视频,包括根据语音节奏进行的各种面部表情和头部运动,并超过了最先进的水平。我们的系统包含三个阶段。当然,FACEGOOD Audio2face 部分也可根据自己的喜好进行重新训练,比如你想用自己的声音或其它类型的声音,或者不同于 FACEGOOD 使用的模型绑定作为驱动数据,都可以根据下面提到的流程完成自己专属的动画驱动算法模型训练。兼顾生成的韵律和外表的相似,除了面部,考虑到了头部的动作,虑了背景区域的artifact。

南七小僧的学海无涯 3051

【DEIM创新改进】全网首发、独家特征融合创新改进篇 | CVPR2025 | 引入RLAB残差线性注意力特征融合块,有效融合并强调多尺度特征,有效减少信息丢失,助力DEIM目标检测有效涨点

本文提出了一种改进DEIM网络模型的新方法RLAB(残差线性注意力特征融合模块),用于医学图像生物标志物分割。RLAB模块通过多尺度残差精炼和注意力机制,有效整合编码器跳跃连接与解码器特征图,提升特征对齐和关键区域关注能力。实验表明,该方法在MoNuSeg、DSB等四个医学图像数据集上显著优于现有方法,最高提升4.03%的绝对性能。文章详细介绍了RLAB的网络结构、核心代码实现方式,并提供了将模块集成到DEIM模型的具体步骤。

Ai缝合怪、助力小伙伴高效发论文 349

SpringSecurity过滤器SecurityContextPersistenceFilter

SecurityContextPersistenceFilter是承接容器的session与spring security的重要filter,主要工作是从session中获取SecurityContext,然后放到上下文中,之后的filter大多依赖这个来获取登录态。其主要是通过HttpSessionSecurityContextRepository来存取的。 public class SecurityContextPersistenceFilter extends GenericFilterBean {

clyu的博客 3013

226届数字IC秋招笔试面试全攻略

本文系统介绍了数字IC设计岗位面试的核心技巧,聚焦三大关键环节:自我介绍、项目介绍和技术问题回答。在自我介绍部分,强调1-2分钟结构化表达,突出与岗位匹配的技能和量化成果;项目介绍环节提出"背景-职责-技术-难点-成果"五步框架,建议结合架构图和性能数据展示技术深度;技术问题回答策略包括理解问题、结构化思考、举例说明和诚实应对未知。文章还提供了项目包装方法,指导如何通过量化数据、架构创新展示和技术难点解决方案来突出项目亮点,并附有简历项目描述示例和技术问题回答模板,帮助面试者全方位展示专

2301_79143213的博客 1062

三、Spring Security过滤器链

一、Spring Security常用过滤器介绍 过滤器是一种典型的AOP思想,关于什么是过滤器,就不再赘述了。 Spring Security中过滤器的介绍: org.springframework.security.web.context.SecurityContextPersistenceFilter 首当其冲的一个过滤器,作用之重要,自不必多言。 SecurityContextPersistenceFilter主要是使用SecurityContextRepository在session中保存或更新

付之一笑的专栏 3519

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

三、Spring Boot集成Spring Security之过滤器链详解

Spring Security过滤器链详解

JavaEE技术进阶之路 1701

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

SpringSecurity过滤器链SecurityContextPersistenceFilter

SecurityContextPersistenceFilter SecurityContextPersistenceFilter是Springsecurity链中第二道防线,位于WebAsyncManagerIntegrationFilter之后,作用是为了存储SecurityContext而设计的。 SecurityContextPersistenceFilter主要做两件事: 当请求到来时,从HttpSession中获取SecurityContext并存入SecurityContextHolder中

sdaujsj1的博客 1150

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

【Spring Security系列】Spring Security 过滤器详解与基于JDBC的认证实现

Spring Security 的过滤器链由多个过滤器组成,每个过滤器负责处理特定的安全任务。当请求到达应用程序时,它会依次通过过滤器链中的每个过滤器,直到到达目标资源。在过滤器链中,每个过滤器都可以对请求进行拦截、修改或执行其他操作,以确保应用程序的安全性。:负责将安全上下文存储在HttpSession中,以便在后续请求中访问。:处理基于表单的身份验证。它拦截包含用户名和密码的请求,并执行身份验证过程。:处理注销请求,清除安全上下文和会话数据。:捕获并处理认证和授权过程中发生的异常。

小威的博客 1万+

Spring Security(四) 核心过滤器源码深度解析

本文系统介绍了Spring Security过滤器链的实现机制与核心组件。过滤器链通过SecurityContextPersistenceFilter、UsernamePasswordAuthenticationFilter等有序执行的安全过滤器,提供身份认证、授权、会话管理等安全功能。文章详细解析了各核心过滤器的源码实现,包括安全上下文持久化、表单登录认证、Basic认证等处理逻辑,并阐述了过滤器链的构建过程与默认执行顺序。同时介绍了如何开发自定义过滤器(如JWT认证)并集成到安全体系中,以及调试监控过滤

油墨香^-^的博客 935

SpringSecurity核心过滤器-SecurityContextPersistenceFilter

Spring Security核心过滤器与安全上下文管理 摘要:本文深入剖析了Spring Security的核心组件及其运行机制。重点讲解了SecurityContextPersistenceFilter的工作原理,该过滤器通过SecurityContextRepository接口实现类(默认HttpSessionSecurityContextRepository)在HTTP会话中管理安全上下文。文章详细阐述了SecurityContextHolder、Authentication、UserDetails

weixin_46300935的博客 316

【微服务架构】SpringSecurity核心源码剖析+jwt+OAuth(九):SpringSecurity核心过滤器-SecurityContextPersistenceFilter

首先用户的认证状态Authentication是存储在SecurityContext中的,而每个用户的SecurityContext是统一存储在HttpSession中的。首先来看看在spring-security-core中的SecurityContextHolder,这个是一个非常基础的对象,存储了当前应用的上下文SecurityContext,而在SecurityContext可以获取Authentication对象。基于上面讲解的三者的关系我们在项目中如此来获取当前登录的用户信息了。

专注上位机开发、机器视觉、机器学习、嵌入式软硬件开发 4万+
上一篇: pg数据库定时备份
下一篇: python制作的一个exe程序——文件对比增量包
varCode
博客等级 码龄9年 11粉丝 15原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值