从源码开始精通spring-security1
参考b站up主:传送门
前沿: 本章:spring-security 重要的成员 WebSecurity、HttpSecurity、SecurityBuilder、SecurityFilterChain、FilterChainProxy
重点:WebSecurity、HttpSecurity 他们都实现了 SecurityBuilder 接口 用来构建对象
WebSecurity的作用:
首先看下他的结构:

public final class WebSecurity extendsAbstractConfiguredSecurityBuilder<Filter, WebSecurity> implementsSecurityBuilder<Filter>, ApplicationContextAware{}
小插曲:其实WebSecurity继承的AbstractConfiguredSecurityBuilder就已经实现了SecurityBuilder也就是说WebSecurity继承AbstractConfiguredSecurityBuilder就已经能完成工作了,再实现一遍SecurityBuilder什么意思?理解:从看代码的人角度 能够更加清晰的知道WebSecurity它实现了SecurityBuilder,是我们最重要的接口而泛型Filter就已经知道要构建的对象是Filter。
总之:我们一下子在这就能看到WebSecurity最终构建的对象Object是什么?就是Filter。
写不写implements SecurityBuilder 对能完成工作
HttpSecurity的作用

用刚才WebSecurity的方法来理解
public final class HttpSecurity extendsAbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>implements SecurityBuilder<DefaultSecurityFilterChain>,HttpSecurityBuilder<HttpSecurity> {}
HttpSecurity是为了构建DefaultSecurityFilterChain对象的。是默认的SecurityFilterChain
SecurityFilterChain
SecurityFilterChain:是一个接口,默认的实现是DefaultSecurityFilterChain
/**
Defines a filter chain which is capable of being matched against an HttpServletRequest. in order to decide whether it applies to that request.
定义这样的一个过滤器链去匹配一个特定的request,然后决定这个request能不能应用这个List<Filter>
*/
public interface SecurityFilterChain {boolean matches(HttpServletRequest request);List<Filter> getFilters();
}
SecurityFilterChain也是spring-security当中重要的一个成员。两个方法:
1、matches 是否能匹配 request
2、匹配成功 那么就getFilters()方法所有的Filter都应用一遍
SecurityFilterChain的默认实现
DefaultSecurityFilterChain
public final class DefaultSecurityFilterChain implements SecurityFilterChain {// 在matches中判断能不能匹配requestprivate final RequestMatcher requestMatcher;private final List<Filter> filters;public DefaultSecurityFilterChain(RequestMatcher requestMatcher, Filter... filters) {this(requestMatcher, Arrays.asList(filters));}public DefaultSecurityFilterChain(RequestMatcher requestMatcher, List<Filter> filters) {logger.info("Creating filter chain: " + requestMatcher + ", " + filters);this.requestMatcher = requestMatcher;this.filters = new ArrayList<>(filters);}public RequestMatcher getRequestMatcher() {return requestMatcher;}// 匹配成功就把Filter应用一遍public List<Filter> getFilters() {return filters;}// 在matches中判断能不能匹配requestpublic boolean matches(HttpServletRequest request) {return requestMatcher.matches(request);}
}
WebSecurity到底构建了怎样的Filter?
public interface SecurityBuilder<O> {/*** Builds the object and returns it or null.** @return the Object to be built or null if the implementation allows it.* @throws Exception if an error occurred when building the Object*/O build() throws Exception;
}
通过build方法看它的实现:AbstractSecurityBuilder实现了SecurityBuilder接口中的build方法
AbstractSecurityBuilder抽象类中 doBuild方法的构建工作委派给子类实现。
public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O>{private AtomicBoolean building = new AtomicBoolean();private O object;//AbstractSecurityBuilder实现了SecurityBuilder接口中的build方法public final O build() throws Exception {if (this.building.compareAndSet(false, true)) {this.object = doBuild();return this.object;}// 解决了重复构建问题 如果再构建一次就抛出异常了throw new AlreadyBuiltException("This object has already been built");}// 构建工作 doBuild 方法protected abstract O doBuild() throws Exception;
}
继续往下走
AbstractConfiguredSecurityBuilder还是一个抽象类。它实现了父类的doBuild方法
public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>>extends AbstractSecurityBuilder<O> {@Overrideprotected final O doBuild() throws Exception {// 加锁 此阶段只能一个线程执行synchronized (configurers) {buildState = BuildState.INITIALIZING;// 留给子类实现的模版方法 不强制子类实现 即不重要的方法beforeInit();init();buildState = BuildState.CONFIGURING;// 留给子类实现的模版方法 不强制子类实现 即不重要的方法beforeConfigure();configure();buildState = BuildState.BUILDING;// 重要方法 有三个类实现它 AuthenticationManagerBuilder HttpSecurity WebSecurityO result = performBuild();buildState = BuildState.BUILT;return result;}} //不强制子类实现protected void beforeInit() throws Exception {}//不强制子类实现protected void beforeConfigure() throws Exception {}// 重要方法protected abstract O performBuild() throws Exception;}
这里通过performBuild();方法构建了我们最终所需要的Object,核心逻辑就在performBuild方法。
有三个类实现它 AuthenticationManagerBuilder、HttpSecurity、 WebSecurity
HttpSecurity的performBuild方法
@Overrideprotected DefaultSecurityFilterChain performBuild() {filters.sort(comparator);return new DefaultSecurityFilterChain(requestMatcher, filters);}
最终返回的就是DefaultSecurityFilterChain 前面说到HttpSecurity所要构建的就是DefaultSecurityFilterChain 那么HttpSecurity的工作完成了。
WebSecurity的performBuild方法
WebSecurity作用:构建一个Filter 显然 构建工作在这
@Overrideprotected Filter performBuild() throws Exception {Assert.state(!securityFilterChainBuilders.isEmpty(),() -> "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. "+ "Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. "+ "More advanced users can invoke "+ WebSecurity.class.getSimpleName()+ ".addSecurityFilterChainBuilder directly");int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);for (RequestMatcher ignoredRequest : ignoredRequests) {securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));}for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {securityFilterChains.add(securityFilterChainBuilder.build());}// FilterChainProxy 就是Filter的一个变种 最终还是一个FilterFilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);if (httpFirewall != null) {filterChainProxy.setFirewall(httpFirewall);}filterChainProxy.afterPropertiesSet();Filter result = filterChainProxy;//debugEnabled:这个是通过 @EnableWebSecurity(dubug=true)开启的if (debugEnabled) {logger.warn("\n\n"+ "********************************************************************\n"+ "********** Security debugging is enabled. *************\n"+ "********** This may include sensitive information. *************\n"+ "********** Do not use in a production system! *************\n"+ "********************************************************************\n\n");result = new DebugFilter(filterChainProxy);}postBuildAction.run();return result;}
FilterChainProxy
前置知识:
SecurityFilterChain:就是一个过滤器链 前面介绍过了 这个过滤器链能否应用就跟请求能不能匹配。
public class FilterChainProxy extends GenericFilterBean {//传了一堆 SecurityFilterChainpublic FilterChainProxy(List<SecurityFilterChain> filterChains) {this.filterChains = filterChains;}// 是Filter的一个主要方法 doFilter做过滤的 控制过滤器只能执行一次@Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;if (clearContext) {try {request.setAttribute(FILTER_APPLIED, Boolean.TRUE);//核心方法 doFilterInternal(request, response, chain);}finally {SecurityContextHolder.clearContext();request.removeAttribute(FILTER_APPLIED);}}else {doFilterInternal(request, response, chain);}}//FilterChain tomcat下的一个接口 他的最主要实现是 ApplicationFilterChainprivate void doFilterInternal(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {FirewalledRequest fwRequest = firewall.getFirewalledRequest((HttpServletRequest) request);HttpServletResponse fwResponse = firewall.getFirewalledResponse((HttpServletResponse) response);// 拿到一堆Filters 这里是重点List<Filter> filters = getFilters(fwRequest);if (filters == null || filters.size() == 0) {if (logger.isDebugEnabled()) {logger.debug(UrlUtils.buildRequestUrl(fwRequest)+ (filters == null ? " has no matching filters": " has an empty filter list"));}fwRequest.reset();chain.doFilter(fwRequest, fwResponse);return;}// VirtualFilterChain 虚拟的过滤器链 chain 最顶层的过滤器链// VirtualFilterChain最终就是 把 这个参数中的 filters 挨个应用一遍VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);// 虚拟的过滤器链 调用了他的 doFilter方法vfc.doFilter(fwRequest, fwResponse);}// 如果应用中定义了多个SecurityFilterChain 如果想要第一个匹配的去执行 此时需要控制一下顺序 实现Order接口 或者Order注解控制?private List<Filter> getFilters(HttpServletRequest request) {for (SecurityFilterChain chain : filterChains) {// 匹配到第一个即成功if (chain.matches(request)) {return chain.getFilters();}}return null;}@Overridepublic void doFilter(ServletRequest request, ServletResponse response)throws IOException, ServletException {if (currentPosition == size) {if (logger.isDebugEnabled()) {logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)+ " reached end of additional filter chain; proceeding with original chain");}// Deactivate path stripping as we exit the security filter chainthis.firewalledRequest.reset();originalChain.doFilter(request, response);}else {currentPosition++;Filter nextFilter = additionalFilters.get(currentPosition - 1);if (logger.isDebugEnabled()) {logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)+ " at position " + currentPosition + " of " + size+ " in additional filter chain; firing Filter: '"+ nextFilter.getClass().getSimpleName() + "'");}nextFilter.doFilter(request, response, this);}}}
}
最后
至此spring-security流程分析完毕 它最顶层就是一个Filter 这个Filter就是FilterChainProxy。
FilterChainProxy里面有一堆的SecurityFilterChain private List<SecurityFilterChain> filterChains;(这个是FilterChainProxy类中的属性),这些SecurityFilterChain都有一个匹配器叫做RequestMatcher,这个RequestMatcher是 SecurityFilterChain的默认实现类DefaultSecurityFilterChain中的属性。
RequestMatcher 是一个接口 有若干个实现 它就是用来匹配请求的。
流程总结:
由FilterChainProxy进来通过调用doFilter方法-进去再调用doFilterInternal方法-通过getFilters 根据HttpServletRequest这个对象去匹配第一个能够匹配的SecurityFilterChain 把其中Filters拿出来。
构建成了一个VirtualFilterChain对象 挨个调用他们的doFilter。
相关文章:
从源码开始精通spring-security1
参考b站up主:传送门 前沿: 本章:spring-security 重要的成员 WebSecurity、HttpSecurity、SecurityBuilder、SecurityFilterChain、FilterChainProxy 重点:WebSecurity、HttpSecurity 他们都实现了 SecurityBuilder 接口 用来构建对象 WebSe…...
你应该优化的JavaScript代码,以及前端工程师日常使用的小技巧。使之更加简洁,可读性更强,更易维护。
本文主要是分享一下平时前端工程师,在写前端代码过程中的一些代码优化,以及使用的一些小技巧,来使我们的代码更加简洁,可读性更强,更易维护。 1. 字符串的自动匹配(includes的优化) includes是…...
自动化测试
文章目录前言一、什么是自动化测试?一个简单的自动化实例二、自动化测试的分类1.接口自动化测试2.UI自动化测试(界面测试)移动端自动化测试web端自动化测试(主要学习)三、selenium工具1.为什么选择selenium作为web自动…...
leetcode-每日一题-807(中等,数组)
正常情况第一眼看这道题,看懂意思的话很简单就可以解出来。给你一座由 n x n 个街区组成的城市,每个街区都包含一座立方体建筑。给你一个下标从 0 开始的 n x n 整数矩阵 grid ,其中 grid[r][c] 表示坐落于 r 行 c 列的建筑物的 高度 。城市的…...
【Linux】Linux项目自动化构建工具make makefile
文章目录1. 背景2.实例3.原理4.项目清理5. 文件属性中的三个时间6. Linux下第一个小程序——进度条6.1 前置知识1:缓冲区6.2前置知识2:回车换行6.3进度条的实现7 Linux下git的”三板斧“1. 背景 一个工程中的源文件不计其数,其按类型、功能、…...
华为OD机试题 - IPv4 地址转换成整数(JavaScript)| 含思路
华为OD机试题 最近更新的博客使用说明本篇题解: IPv4 地址转换成整数题目输入输出示例一输入输出说明示例一输入输出说明Code解题思路华为OD其它语言版本最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | …...
spring整合通用mapper
1.使用通用mapper可以更快速的进行数据库的增删查改操作,加入springboot的管理,常规的SQL都可以复用 2.整合 a)引入依赖 <dependencies><dependency><groupId>tk.mybatis</groupId><artifactId>mapper-spring-boot-starter</artifactId>…...
一天什么时间发抖音浏览量高?5个抖音最佳发布时间段
抖音作为现在一款现象级的软件,已经不知不觉地影响着我们生活的方方面面。那抖音想要被更多人看到,就需要掐准哪些时间活跃数最多,今天就来和大家分享一下一天什么时间发抖音浏览量高,又该如何抓住最佳投放契机呢?一、一天什么时…...
华为OD机试题 - 关联子串(JavaScript)| 含思路
华为OD机试题 最近更新的博客使用说明本篇题解:关联子串题目输入输出示例一输入输出说明示例二输入输出说明Code解题思路华为OD其它语言版本最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典...
【代码随想录训练营】【Day33休息】【Day34】第八章|贪心算法|1005.K次取反后最大化的数组和|134. 加油站|135. 分发糖果
K 次取反后最大化的数组和 题目详细:LeetCode.1005 这道题比较简单,这里直接给出贪心策略: 局部最优解: 按照 负数 > 0 > 正数 的优先级次序,依次对nums中的较小数值进行取反因为负负得正,负值越小…...
<c++> const 常量限定符
文章目录什么是 const 常量限定符const 的初始化const 的默认作用域const 的引用例外情况const 与指针const指针的声明指向 const 的指针const指针指向 const 的 const指针什么是 const 常量限定符 Q:什么是 const 常量限定符? A:const名叫常…...
pytorch实现transformer模型
Transformer是一种强大的神经网络架构,可用于处理序列数据,例如自然语言处理任务。在PyTorch中,可以使用torch.nn.Transformer类轻松实现Transformer模型。 以下是一个简单的Transformer模型实现的示例代码,它将一个输入序列转换为…...
【懒加载数据 Objective-C语言】
一、咱们就开始进行懒加载 1.懒加载发现,每一个字典,是不是就是四个键值对组成的: 1)answer:String,中国合伙人, 2)icon:String,movie_zghhr, 3)title:String,创业励志电影, 4)options:Array,21 items 前三个都是String类型,最后是不是Array类型, 所…...
人脸网格/人脸3D重建 face_mesh(毕业设计+代码)
概述 Face Mesh是一个解决方案,可在移动设备上实时估计468个3D面部地标。它利用机器学习(ML)推断3D面部表面,只需要单个摄像头输入,无需专用深度传感器。利用轻量级模型架构以及整个管道中的GPU加速,该解决…...
JMeter 控制并发数
文章目录一、误区二、正确设置 JMeter 的并发数总结没用过 JMeter 的同学,可以先过一遍他的简单使用例子 https://blog.csdn.net/weixin_42132143/article/details/118875293?spm1001.2014.3001.5501 一、误区 在使用 JMeter 做压测时,大家都知道要这么…...
git常用命令汇总
Git 是一种分布式版本控制系统,它具有以下优点: 分布式:每个开发者都可以拥有自己的本地代码仓库,不需要连接到中央服务器,这样可以避免单点故障和网络延迟等问题。 非线性开发:Git 可以支持多个分支并行开…...
【2023】华为OD机试真题Java-题目0226-寻找相似单词
寻找相似单词 题目描述 给定一个可存储若干单词的字典,找出指定单词的所有相似单词,并且按照单词名称从小到大排序输出。单词仅包括字母,但可能大小写并存(大写不一定只出现在首字母)。 相似单词说明:给定一个单词X,如果通过任意交换单词中字母的位置得到不同的单词Y,…...
【项目管理】晋升为领导后,如何开展工作?
兵随将转,作为管理者,你可以不知道下属的短处,却不能不知道下属的长处。晋升为领导后,如何开展工作呢? 金九银十,此期间换工作的人不在少数。有几位朋友最近都换了公司,职位得到晋升,…...
JAVA开发(Spring Gateway 的原理和使用)
在springCloud的架构中,业务服务都是以微服务来划分的,每个服务可能都有自己的地址和端口。如果前端或者说是客户端直接去调用不同的微服务的话,就要配置不同的地址。其实这是一个解耦和去中心化出现的弊端。所以springCloud体系中࿰…...
踩坑:解决npm版本升级报错,无法安装node-sass的问题
npm版本由于经常更新,迁移前端项目时经常发现报错安装不上。 比如,项目经常使用的sass模块,可能迁移的时候就发现安装不了。 因为node-sass 编译器是通过 C 实现的。在 Node.js 中,采用 gyp 构建工具进行构建 C 代码,…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...
Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)
macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 🍺 最新版brew安装慢到怀疑人生?别怕,教你轻松起飞! 最近Homebrew更新至最新版,每次执行 brew 命令时都会自动从官方地址 https://formulae.…...
脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)
一、OpenBCI_GUI 项目概述 (一)项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台,其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言,首次接触 OpenBCI 设备时,往…...
