新版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…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...
