新版Spring Security6.2架构 (一)
Spring Security
新版springboot 3.2已经集成Spring Security 6.2,和以前会有一些变化,本文主要针对官网的文档进行一些个人翻译和个人理解,不对地方请指正。
整体架构
Spring Security的Servlet 支持是基于Servelet过滤器,如下图所示,当http请求到来时候,会经历下面的过滤器。

客户端发送请求到应用程序,容器会生成过滤链(其中包含过滤器实例)并且会根据URL地址处理httpServletRequest。在Spring MVC应用程序中,Servlet是DispatcherServlet的实例,一个Servlet最多可以处理一个HttpServletRequest 和 HttpServletResponse. 但是使用的过滤器不止一个,主要有以下两点:
1.防止下游过滤器实例或者Servlet被调用,这种情况下,过滤器通常会写入HttpServletResponse.
2.修改HttpServletRequest 和 HttpServletRespons,并且传递给下游过滤器和Servlet.
过滤器强大在于传递给它的过滤器链。
过滤器链的例子:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {// do something before the rest of the applicationchain.doFilter(request, response); // invoke the rest of the application// do something after the rest of the application
}
官网这段话,其实看这个图或者说和servlet的过滤器执行顺序相关,图里所示就是Filter0->Filter1->Filter2->Servlet,所以使用过滤器是多个的,并且要按照过滤器顺序往下传递,每个过滤器最重要是重写doFilter, 并且这个函数参数有过滤器链FilterChain,每个过滤器在做完自己事情(do something before)后,就得传递给过滤器链,chain.doFilter,保证往下传递。相反,回来的时候肯定相反方向:Servelet->Filter2->Filter1->Filter0。
DelegatingFilterProxy
Spring提供了一个过滤器叫DelegatingFilterProxy,它链接了Servlet容器的生命周期和Spring applicationContext。Servlet容器有自己的标准,可以注册Filter过滤器实例,但是它没有办法找到Spring所定义的Beans对象。你可以注册DelegatingFilterProxy,并且它符合Servlet容器机制,还能委托给Spring Bean所实现的Filter过滤器。

DelegatingFilterProxy会从AllicationContext查找Bean Filter0并且调用Bean Filter0过滤器
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {Filter delegate = getFilterBean(someBeanName); //1delegate.doFilter(request, response); //2
}
1.惰性获取已经注册Spring Bean的Filter
2.将工作委托给Spring Bean
DelegatingFilterProxy另个好处就是允许延迟查询Filter实例。这个是很重要的,因为容器需要在容器启动前注册Filter实例,但是,Spring 通常使用 ContextLoaderListener 来加载 Spring Bean,直到需要注册 Filter 实例之后才会执行此操作。
FilterChainProxy
Spring Security的Servelet 支持都被包含在了FilterChainProxy,FilterChainProxy是一个特殊过滤器,能够通过SecurityFilterChain委托给许多Filter过滤器实例,FilterChainProxy是一个bean,所以通常被包装在DelegatingFilterProxy中。

SecurityFilterChain
SecurityFilterChain被FilterChainProxy使用,并且决定了哪个Spring Security过滤器实例对当前请求进行调用

SecurityFilterChain 中的SecurityFilter通常是 Bean,但它们是使用 FilterChainProxy 而不是 DelegatingFilterProxy 注册的。FilterChainProxy 为直接向 Servlet 容器或 DelegatingFilterProxy 注册提供了许多优势。首先,它为 Spring Security 的所有 Servlet 支持提供了一个起点。因此,如果您尝试对 Spring Security 的 Servlet 支持进行故障排除,在 FilterChainProxy 中添加调试点是一个很好的起点。
其次,由于 FilterChainProxy 是 Spring Security 使用的核心,因此它可以执行不被视为可选的任务。例如,它会清除 SecurityContext 以避免内存泄漏。它还应用 Spring Security 的 HttpFirewall 来保护应用程序免受某些类型的攻击。
此外,它还在确定何时应调用 SecurityFilterChain 方面提供了更大的灵活性。在 Servlet 容器中,仅根据 URL 调用过滤器实例。但是,FilterChainProxy 可以使用 RequestMatcher 接口根据 HttpServletRequest 中的任何内容确定调用。
在多个 SecurityFilterChain 图中,FilterChainProxy 决定应使用哪个 SecurityFilterChain。仅调用匹配的第一个 SecurityFilterChain。如果请求 /api/messages/ 的 URL,则它首先与 /api/** 的 SecurityFilterChain0 模式匹配,因此仅调用 SecurityFilterChain0,即使它在 SecurityFilterChainn 上也匹配。如果请求 /messages/ 的 URL,则它与 /api/** 的 SecurityFilterChain0 模式不匹配,因此 FilterChainProxy 会继续尝试每个 SecurityFilterChain。假设没有其他 SecurityFilterChain 实例匹配,则调用 SecurityFilterChaann。
请注意,SecurityFilterChain0 只配置了三个security Filter实例。但是,SecurityFilterChainn 配置了四个安全筛选器实例。需要注意的是,每个 SecurityFilterChain 都可以是唯一的,并且可以单独配置。事实上,如果应用程序希望 Spring Security 忽略某些请求,则 SecurityFilterChain 可能具有零安全过滤器实例。
SecurityFilter
security Filters使用 SecurityFilterChain API 插入到 FilterChainProxy 中。这些过滤器可用于多种不同的目的,例如身份验证、授权、漏洞利用保护等。过滤器按特定顺序执行,以保证在正确的时间调用它们,例如,执行身份验证的过滤器应先调用,然后再调用执行授权的过滤器。通常没有必要知道 Spring Security 过滤器的顺序。但是,有时了解排序是有益的,如果您想了解它们,可以查看 FilterOrderRegistration 代码。
为了举例说明上述段落,让我们考虑以下安全配置:
@Configuration
@EnableWebSecurity
public class SecurityConfig {@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.csrf(Customizer.withDefaults()).authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated()).httpBasic(Customizer.withDefaults()).formLogin(Customizer.withDefaults());return http.build();}}
上面的配置就会导致如下的过滤器的顺序
| Filter | Added by |
|---|---|
| CsrfFilter |
|
| UsernamePasswordAuthenticationFilter |
|
| BasicAuthenticationFilter |
|
| AuthorizationFilter |
|
1.调用 CsrfFilter 来防止 CSRF 攻击。
2.调用身份验证筛选器来对请求进行身份验证。
3.调用 AuthorizationFilter 来授权请求。
添加自定义的过滤器
大多数情况下,默认安全筛选器足以为应用程序提供安全性。但是,有时您可能希望将自定义筛选器添加到安全筛选器链。
例如,假设你要添加一个获取租户 ID 标头的筛选器,并检查当前用户是否有权访问该租户。前面的描述已经为我们提供了在何处添加过滤器的线索,因为我们需要知道当前用户,因此我们需要在身份验证过滤器之后添加它。
首先,让我们创建过滤器:
public class TenantFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;String tenantId = request.getHeader("X-Tenant-Id"); //1boolean hasAccess = isUserAllowed(tenantId); //2if (hasAccess) {filterChain.doFilter(request, response); //3return;}throw new AccessDeniedException("Access denied"); //4 }}
面的示例代码执行以下操作:
1.从请求标头中获取租户 ID。
2.检查当前用户是否有权访问租户 ID。
3.如果用户具有访问权限,则调用链中的其余筛选器。
4.如果用户没有访问权限,则引发 AccessDeniedException。
官网还给了一个建议,可以从 OncePerRequestFilter 进行扩展,而不是实现 Filter,OncePerRequestFilter 是每个请求仅调用一次的过滤器的基类,并提供带有 HttpServletRequest 和 HttpServletResponse 参数的 doFilterInternal 方法。
这个建议,主要是因为servlet filter因为版本不同,以及不同web container,一个请求不一定只过一个fitler,像servlet2.3中,Filter会经过一切请求,包括服务器内部使用forward.
最后在把上面自定义的过滤器加到过滤器链中.
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http// ....addFilterBefore(new TenantFilter(), AuthorizationFilter.class); return http.build();
}
HttpSecurity会通过addFilterBefore在AuthorizationFilter前添加TenanFilter.
通过在 AuthorizationFilter 之前添加过滤器,我们可以确保在身份验证过滤器之后调用 TenantFilter。您还可以使用 HttpSecurity的addFilterAfter 在特定过滤器之后添加过滤器,或使用 HttpSecurity的addFilterAt 在过滤器链中的特定过滤器位置添加过滤器。
将过滤器声明为 Spring Bean 时要小心,不管用 @Component 注解或在配置中将其声明为 Bean,因为 Spring Boot 会自动将其注册到嵌入式容器中。这可能会导致过滤器被调用两次,一次由容器调用,一次由 Spring Security 调用,并且顺序不同。
例如,如果您仍然希望将过滤器声明为 Spring Bean 以利用依赖注入,并避免重复调用,您可以通过声明 FilterRegistrationBean bean 并将其 enabled 属性设置为 false 来告诉 Spring Boot 不要将其注册到容器中:
@Bean
public FilterRegistrationBean<TenantFilter> tenantFilterRegistration(TenantFilter filter) {FilterRegistrationBean<TenantFilter> registration = new FilterRegistrationBean<>(filter);registration.setEnabled(false);return registration;
}
处理异常
ExceptionTranslationFilter 允许将 AccessDeniedException 和 AuthenticationException 转换为 HTTP 响应。
ExceptionTranslationFilter 作为安全过滤器之一插入到 FilterChainProxy 中。

1.ExceptionTranslationFilter 调用 FilterChain.doFilter(request, response) 来调用应用程序的其余部分。
2.如果用户未通过身份验证或它是 AuthenticationException,则启动Authentication。(1)SecurityContextHolder 被清除。
(2)保存 HttpServletRequest,以便在Authentication验证成功后使用它来重播原始请求。
(3)AuthenticationEntryPoint 用于从客户端请求凭据。例如,它可能会重定向到登录页面或发送 WWW-Authenticate 标头。
3.否则,如果它是 AccessDeniedException,则拒绝访问。调用 AccessDeniedHandler 来处理被拒绝的访问。
如果应用程序未引发 AccessDeniedException 或 AuthenticationException,则 ExceptionTranslationFilter 不会执行任何操作。
try {filterChain.doFilter(request, response);
} catch (AccessDeniedException | AuthenticationException ex) {if (!authenticated || ex instanceof AuthenticationException) {startAuthentication(); } else {accessDenied(); }
}
1. 调用 FilterChain.doFilter(request, response) 等同于调用应用程序的其余部分。这意味着,如果应用程序的另一部分(FilterSecurityInterceptor 或方法安全性)引发 AuthenticationException 或 AccessDeniedException,则会在此处捕获并处理它。
2.如果用户未经过身份验证或是 AuthenticationException,则启动身份验证。
3.否则,访问被拒绝
在Authentication中保持请求
如处理安全异常中所示,当请求没有身份验证并且针对需要身份验证的资源时,需要保存身份验证资源的请求,以便在身份验证成功后重新请求。在 Spring Security 中,这是通过使用 RequestCache 实现保存 HttpServletRequest 来完成的。
RequestCache
HttpServletRequest 保存在 RequestCache 中。当用户成功进行身份验证时,RequestCache 将用于重播原始请求。RequestCacheAwareFilter 是使用 RequestCache 保存 HttpServletRequest 的。
默认情况下,使用 HttpSessionRequestCache。下面的代码演示如何自定义 RequestCache 实现,该实现用于检查 HttpSession 中是否存在名为 continue 的参数时已保存的请求。
@Bean
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {HttpSessionRequestCache requestCache = new HttpSessionRequestCache();requestCache.setMatchingRequestParameterName("continue");http// ....requestCache((cache) -> cache.requestCache(requestCache));return http.build();
}
防止请求被保存
您可能希望不要在会话中存储用户未经身份验证的请求,原因有很多。您可能希望将该存储卸载到用户的浏览器上,或将其存储在数据库中。或者,您可能希望关闭此功能,因为您始终希望将用户重定向到主页,而不是他们在登录前尝试访问的页面。
为此,可以使用 NullRequestCache 实现。
@Bean
SecurityFilterChain springSecurity(HttpSecurity http) throws Exception {RequestCache nullRequestCache = new NullRequestCache();http// ....requestCache((cache) -> cache.requestCache(nullRequestCache));return http.build();
}
Spring Boot Security Get started
@EnableWebSecurity //1
@Configuration
public class DefaultSecurityConfig {@Bean@ConditionalOnMissingBean(UserDetailsService.class)InMemoryUserDetailsManager inMemoryUserDetailsManager() { //2String generatedPassword = // ...;return new InMemoryUserDetailsManager(User.withUsername("user").password(generatedPassword).roles("ROLE_USER").build());}@Bean@ConditionalOnMissingBean(AuthenticationEventPublisher.class)DefaultAuthenticationEventPublisher defaultAuthenticationEventPublisher(ApplicationEventPublisher delegate) { //3return new DefaultAuthenticationEventPublisher(delegate);}
}
1.使用EnableWebSecurity注册Spring Security's 注册默认的过滤链(default filter chain)对应的bean
2.第二个就是注册一个UserDetailsService默认bean,现在注册是默认的内存里面用户和密码
3.注册一个authenticationEventPublisher的bean对象给authentication 事件
相关文章:
新版Spring Security6.2架构 (一)
Spring Security 新版springboot 3.2已经集成Spring Security 6.2,和以前会有一些变化,本文主要针对官网的文档进行一些个人翻译和个人理解,不对地方请指正。 整体架构 Spring Security的Servlet 支持是基于Servelet过滤器,如下…...
名字的漂亮度
给出一个字符串,该字符串仅由小写字母组成,定义这个字符串的“漂亮度”是其所有字母“漂亮度”的总和。 每个字母都有一个“漂亮度”,范围在1到26之间。没有任何两个不同字母拥有相同的“漂亮度”。字母忽略大小写。给出多个字符串࿰…...
机器学习基本概念2
资料来源: https://www.youtube.com/watch?vYe018rCVvOo&listPLJV_el3uVTsMhtt7_Y6sgTHGHp1Vb2P2J&index1 https://www.youtube.com/watch?vbHcJCp2Fyxs&listPLJV_el3uVTsMhtt7_Y6sgTHGHp1Vb2P2J&index2 分三步 1、 定义function b和w是需要透…...
Spring Cloud 与微服务学习总结(19)—— Spring Cloud Alibaba 之 Nacos 2.3.0 史上最大更新版本发布
Nacos 一个用于构建云原生应用的动态服务发现、配置管理和服务管理平台,由阿里巴巴开源,致力于发现、配置和管理微服务。说白了,Nacos 就是充当微服务中的的注册中心和配置中心。 Nacos 2.3.0 新特性 1. 反脆弱插件 Nacos 2.2.0 版本开始加入反脆弱插件,从 2.3.0 版本开…...
八、C#笔记
/// <summary> /// 第十三章:创建接口和定义抽象类 /// </summary> namespace Chapter13 { class Program { static void Main(string[] args) { //13.1理解接口 ///13.1.1定义接口 ///…...
利用Node.js和cpolar实现远程访问,无需公网IP和路由器设置的完美解决方案
文章目录 前言1.安装Node.js环境2.创建node.js服务3. 访问node.js 服务4.内网穿透4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5.固定公网地址 前言 Node.js 是能够在服务器端运行 JavaScript 的开放源代码、跨平台运行环境。Node.js 由 OpenJS Foundation࿰…...
C++如何通过调用ffmpeg接口对H264文件进行编码和解码
C可以通过调用FFmpeg的API来对H264文件进行编码和解码。下面是一个简单的例子。 首先需要在代码中包含FFmpeg的头文件: extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswscale/swscale…...
使用MetaMask + Ganache搭建本地私有网络并实现合约部署与互动
我使用Remix编写合约,MetaMask钱包工具和Ganache搭建了一个私有网络,并且实现了合约的部署和互动。 在前面的博客中提到了 Remix在线环境及钱包申请 以及 Solidity的基本语法 ,没看过的小伙伴可以点击链接查看一下,都是在本专栏下…...
目标检测、目标跟踪、重识别
文章目录 环境前言项目复现特征提取工程下载参考资料 环境 ubuntu 18.04 64位yolov5deepsortfastreid 前言 基于YOLOv5和DeepSort的目标跟踪 介绍过针对行人的检测与跟踪。本文介绍另一个项目,结合 FastReid 来实现行人的检测、跟踪和重识别。作者给出的2个主…...
高防IP防御效果怎么样,和VPN有区别吗
高防IP主要是用于防御网络攻击,可以抵御各种类型的DDoS攻击,隐藏源IP地址,提高网络安全性和用户体验。主要目的是解决外部网络攻击问题,保护网络安全,避免因攻击而导致的业务中断和数据泄露等问题。 而VPN则是一种可以…...
探秘MSSQL存储过程:功能、用法及实战案例
在现代软件开发中,高效地操作数据库是至关重要的。而MSSQL(Microsoft SQL Server)作为一款强大的关系型数据库管理系统,为我们提供了丰富的功能和工具来处理数据。其中,MSSQL存储过程是一项强大而又常用的功能…...
我们常说的流应用到底是什么?
流应用是DCloud公司开发的一种可以让手机App安装包实现边用边下的技术。基于HTML5规范的即点即用应用,开发者按照HTML5规范开发的应用,可以在支持HTML5流应用的发行渠道实现即点即用的效果。 流应用是基于 HTML5规范的即点即用应用,开发者按照…...
ELK 日志解决方案
ELK 是目前最流行的集中式日志解决方案,提供了对日志收集、存储、展示等一站式的解决方案。 ELK 分别指 Elasticsearch、Logstash、Kibana。 Elasticsearch:分布式数据搜索引擎,基于 Apache Lucene 实现,可集群,提供…...
本项目基于Spring boot的AMQP模块,整合流行的开源消息队列中间件rabbitMQ,实现一个向rabbitMQ
在业务逻辑的异步处理,系统解耦,分布式通信以及控制高并发的场景下,消息队列有着广泛的应用。本项目基于Spring的AMQP模块,整合流行的开源消息队列中间件rabbitMQ,实现一个向rabbitMQ添加和读取消息的功能。并比较了两种模式&…...
freeswitch webrtc video_demo客户端进行MCU的视频会议
系统环境 一、编译服务器和加载模块 二、下载编译指定版本video_demo 三、配置verto.conf.xml 1.修改配置文件 2.重新启动 四、MCU通话测试 1.如何使用video_demo 2.测试结果 五、MCU的通话原理及音频/视频/布局/管理员等参数配置 附录 freeswitch微信交流群 系统环境 lsb_rel…...
【鸿蒙学习网络】
鸿蒙技术学习相关学习资料 官方文档:华为官方提供了鸿蒙开发者文档,包括开发指南、API参考和示例代码等。您可以访问华为开发者中心网站(https://developer.harmonyos.com/)获取最新的官方文档和教程。在 线 课 程 : …...
MySQL系列(一):索引篇
为什么是B树? 我们推导下,首先看下用哈希表做索引,是否可以满足需求。如果我们用哈希建了索引,那么对于如下这种SQL,通过哈希,可以快速检索出数据: select * from t_user_info where id1;但是这…...
Flink Flink数据写入Kafka
一、环境准备 官网地址 flink官方集成了通用的 Kafka 连接器,使用时需要根据生产环境的版本引入相应的依赖 <properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><flink.version>1.14.6</flink.version&g…...
《论文阅读》用于情绪回复生成的情绪正则化条件变分自动编码器 Affective Computing 2021
《论文阅读》用于情绪回复生成的情绪正则化条件变分自动编码器 前言简介模型结构实验结果总结前言 今天为大家带来的是《Emotion-Regularized Conditional Variational Autoencoder for Emotional Response Generation》 出版:IEEE Transactions on Affective Computing 时间…...
Pytorch CIFAR10图像分类 Swin Transformer篇
Pytorch CIFAR10图像分类 Swin Transformer篇 文章目录 Pytorch CIFAR10图像分类 Swin Transformer篇4. 定义网络(Swin Transformer)Swin Transformer整体架构Patch MergingW-MSASW-MSARelative position biasSwin Transformer 网络结构Patch EmbeddingP…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
