当前位置: 首页 > news >正文

5.深入理解HttpSecurity的设计

深入理解HttpSecurity的设计

一、HttpSecurity的应用

  在前章节的介绍中我们讲解了基于配置文件的使用方式,也就是如下的使用。

image.png

  也就是在配置文件中通过 security:http 等标签来定义了认证需要的相关信息,但是在SpringBoot项目中,我们慢慢脱离了xml配置文件的方式,在SpringSecurity中提供了HttpSecurity等工具类,这里HttpSecurity就等同于我们在配置文件中定义的http标签。要使用的话方式如下。

image.png

  通过代码结果来看和配置文件的效果是一样的。基于配置文件的方式我们之前分析过,是通过标签对应的handler来解析处理的,那么HttpSecurity这块是如何处理的呢?我们来详细分析下。

二、HttpSecurity的类图结构

image.png

  可以看出HttpSecurity的类图结构相对比较简单,继承了一个父类,实现了两个接口。我们分别来看看他们的作用是什么?

1.SecurityBuilder接口

  我们先来看看SecurityBuilder接口,通过字面含义我们就可以发现这是一个帮我们创建对象的工具类。

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;}

  通过源码我们可以看到在SecurityBuilder中给我们提供了一个build()方法。在接口名称处声明了一个泛型,而build()方法返回的正好是这个泛型的对象,其实就很好理解了,也就是SecurityBuilder会创建指定类型的对象。结合HttpSecurity中实现SecurityBuilder接口时指定的泛型我们可以看出创建的具体对象是什么类型。

image.png

  可以看出SecurityBuilder会通过build方法给我们创建一个DefaultSecurityFilterChain对象。也就是拦截请求的那个默认的过滤器链对象。

image.png

然后进入到doBuild()方法,会进入到AbstractConfiguredSecurityBuilder中的方法

	@Overrideprotected final O doBuild() throws Exception {synchronized (this.configurers) {this.buildState = BuildState.INITIALIZING;beforeInit();init();this.buildState = BuildState.CONFIGURING;beforeConfigure();configure();this.buildState = BuildState.BUILDING;// 获取构建的对象,上面的方法可以先忽略O result = performBuild();this.buildState = BuildState.BUILT;return result;}}

进入到HttpSecurity中可以查看performBuild()方法的具体实现。

	@Overrideprotected DefaultSecurityFilterChain performBuild() {// 对所有的过滤器做排序this.filters.sort(OrderComparator.INSTANCE);List<Filter> sortedFilters = new ArrayList<>(this.filters.size());for (Filter filter : this.filters) {sortedFilters.add(((OrderedFilter) filter).filter);}// 然后生成 DefaultSecurityFilterChainreturn new DefaultSecurityFilterChain(this.requestMatcher, sortedFilters);}

在构造方法中绑定了对应的请求匹配器和过滤器集合。

image.png

对应的请求匹配器则是 AnyRequestMatcher 匹配所有的请求。当然我们会比较关心默认的过滤器链中的过滤器是哪来的,这块儿我们继续来分析。

2.AbstractConfiguredSecurityBuilder

  然后我们再来看看AbstractConfiguredSecurityBuilder这个抽象类,他其实是SecurityBuilder的实现,在这儿需要搞清楚他们的关系。

image.png

类型作用
SecurityBuilder声明了build方法
AbstractSecurityBuilder提供了获取对象的方法以及控制一个对象只能build一次
AbstractConfiguredSecurityBuilder除了提供对对象细粒度的控制外还扩展了对configurer的操作

然后对应的三个实现类。

image.png

首先 AbstractConfiguredSecurityBuilder 中定义了一个枚举类,将整个构建过程分为 5 种状态,也可
以理解为构建过程生命周期的五个阶段,如下:

private enum BuildState {/*** 还没开始构建*/UNBUILT(0),/*** 构建中*/INITIALIZING(1),/*** 配置中*/CONFIGURING(2),/*** 构建中*/BUILDING(3),/*** 构建完成*/BUILT(4);private final int order;BuildState(int order) {this.order = order;}public boolean isInitializing() {return INITIALIZING.order == this.order;}/*** Determines if the state is CONFIGURING or later* @return*/public boolean isConfigured() {return this.order >= CONFIGURING.order;}}

通过这些状态来管理需要构建的对象的不同阶段。

2.1 add方法

  AbstractConfiguredSecurityBuilder中方法概览

image.png

  我们先来看看add方法。

private <C extends SecurityConfigurer<O, B>> void add(C configurer) {Assert.notNull(configurer, "configurer cannot be null");Class<? extends SecurityConfigurer<O, B>> clazz = (Class<? extends SecurityConfigurer<O, B>>) configurer.getClass();synchronized (this.configurers) {if (this.buildState.isConfigured()) {throw new IllegalStateException("Cannot apply " + configurer + " to already built object");}List<SecurityConfigurer<O, B>> configs = null;if (this.allowConfigurersOfSameType) {configs = this.configurers.get(clazz);}configs = (configs != null) ? configs : new ArrayList<>(1);configs.add(configurer);this.configurers.put(clazz, configs);if (this.buildState.isInitializing()) {this.configurersAddedInInitializing.add(configurer);}}}/*** Gets all the {@link SecurityConfigurer} instances by its class name or an empty* List if not found. Note that object hierarchies are not considered.* @param clazz the {@link SecurityConfigurer} class to look for* @return a list of {@link SecurityConfigurer}s for further customization*/@SuppressWarnings("unchecked")public <C extends SecurityConfigurer<O, B>> List<C> getConfigurers(Class<C> clazz) {List<C> configs = (List<C>) this.configurers.get(clazz);if (configs == null) {return new ArrayList<>();}return new ArrayList<>(configs);}

  add 方法,这相当于是在收集所有的配置类。将所有的 xxxConfigure 收集起来存储到 configurers
中,将来再统一初始化并配置,configurers 本身是一个 LinkedHashMap ,key 是配置类的 class,
value 是一个集合,集合里边放着 xxxConfigure 配置类。当需要对这些配置类进行集中配置的时候,
会通过 getConfigurers 方法获取配置类,这个获取过程就是把 LinkedHashMap 中的 value 拿出来,
放到一个集合中返回。

2.2 doBuild方法

  然后来看看doBuild方法中的代码

 	@Overrideprotected final O doBuild() throws Exception {synchronized (this.configurers) {this.buildState = BuildState.INITIALIZING;beforeInit(); //是一个预留方法,没有任何实现init(); // 就是找到所有的 xxxConfigure,挨个调用其 init 方法进行初始化this.buildState = BuildState.CONFIGURING;beforeConfigure(); // 是一个预留方法,没有任何实现configure(); // 就是找到所有的 xxxConfigure,挨个调用其 configure 方法进行配置。this.buildState = BuildState.BUILDING;O result = performBuild();
// 是真正的过滤器链构建方法,但是在 AbstractConfiguredSecurityBuilder中 performBuild 方法只是一个抽象方法,具体的实现在 HttpSecurity 中this.buildState = BuildState.BUILT;return result;}}

init方法:完成所有相关过滤器的初始化

	private void init() throws Exception {Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();for (SecurityConfigurer<O, B> configurer : configurers) {configurer.init((B) this); // 初始化对应的过滤器}for (SecurityConfigurer<O, B> configurer : this.configurersAddedInInitializing) {configurer.init((B) this);}}

configure方法:完成HttpSecurity和对应的过滤器的绑定。

	private void configure() throws Exception {Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();for (SecurityConfigurer<O, B> configurer : configurers) {configurer.configure((B) this);}}

3.HttpSecurity

  HttpSecurity 做的事情,就是进行各种各样的 xxxConfigurer 配置

image.png

HttpSecurity 中有大量类似的方法,过滤器链中的过滤器就是这样一个一个配置的。我们就不一一介绍
了。每个配置方法的结尾都会来一句 getOrApply,这个是干嘛的?我们来看下

	private <C extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>> C getOrApply(C configurer)throws Exception {C existingConfig = (C) getConfigurer(configurer.getClass());if (existingConfig != null) {return existingConfig;}return apply(configurer);}

  getConfigurer 方法是在它的父类 AbstractConfiguredSecurityBuilder 中定义的,目的就是去查看当前
这个 xxxConfigurer 是否已经配置过了。
  如果当前 xxxConfigurer 已经配置过了,则直接返回,否则调用 apply 方法,这个 apply 方法最终会调
用到 AbstractConfiguredSecurityBuilder#add 方法,将当前配置 configurer 收集起来
HttpSecurity 中还有一个 addFilter 方法.

	@Overridepublic HttpSecurity addFilter(Filter filter) {Integer order = this.filterOrders.getOrder(filter.getClass());if (order == null) {throw new IllegalArgumentException("The Filter class " + filter.getClass().getName()+ " does not have a registered order and cannot be added without a specified order. Consider using addFilterBefore or addFilterAfter instead.");}this.filters.add(new OrderedFilter(filter, order));return this;}

  这个 addFilter 方法的作用,主要是在各个 xxxConfigurer 进行配置的时候,会调用到这个方法,
(xxxConfigurer 就是用来配置过滤器的),把 Filter 都添加到 fitlers 变量中。

小结:这就是 HttpSecurity 的一个大致工作流程。把握住了这个工作流程,剩下的就只是一些简单的重
复的 xxxConfigurer 配置了

相关文章:

5.深入理解HttpSecurity的设计

深入理解HttpSecurity的设计 一、HttpSecurity的应用 在前章节的介绍中我们讲解了基于配置文件的使用方式&#xff0c;也就是如下的使用。 也就是在配置文件中通过 security:http 等标签来定义了认证需要的相关信息&#xff0c;但是在SpringBoot项目中&#xff0c;我们慢慢脱离…...

opencv-python numpy常见的api接口汇总(持续更新)

前言 最近写代码总是提笔忘api&#xff0c;因为图像处理代码写的比较多&#xff0c;所以想着把一些常用的opencv的api&#xff0c;包括numpy的api做一个记录&#xff0c;后面再忘记的时候&#xff0c;就不用去google挨个搜索了&#xff0c;只需要在自己的博客中一查就全知道了…...

概率论小课堂:伯努利实验(正确理解随机性,理解现实概率和理想概率的偏差)

文章目录 引言I 伯努利试验1.1 伯努利分布(二项式分布)1.2 数学期望值(简称期望值)1.3 平方差(简称方差)1.4 标准差1.5 小结引言 假设买彩票中奖的概率是一百万分之一,如果要想确保成功一次,要买260万次彩票。你即使中一回大奖,花的钱要远比获得的多得多。 很多人喜…...

加密功能实现

文章目录1. 前言2. 密码加密1. 前言 本文 主要实现 对密码进行加密 &#xff0c;因为 使用 md5 容易被穷举 (彩虹表) 而破解 &#xff0c;使用 spring security 框架又太大了 (杀鸡用牛刀) 。   所以本文 就自己实现一个密码加密 . 2. 密码加密 这里我们通过 加盐是方式 来 对…...

大数据项目实战之数据仓库:用户行为采集平台——第1章 数据仓库概念

第1章 数据仓库概念 数据仓库&#xff08;Data Warehouse&#xff09;&#xff0c;是为企业制定决策&#xff0c;提供数据支持的。可以帮助企业改进业务流程、提高产品质量等。 数据仓库的输入数据通常包括&#xff1a;业务数据、用户行为数据和爬虫数据等 业务数据&#xf…...

NTP对时服务器(NTP电子时钟)在生物制药业应用

NTP对时服务器&#xff08;NTP电子时钟&#xff09;在生物制药业应用 NTP对时服务器&#xff08;NTP电子时钟&#xff09;在生物制药业应用 8.1 系统概述 时钟系统为生物制药厂网络控制中心调度员、车场值班员及各部门工作人员提供统一的标准时间信息&#xff0c;也为本工程其它…...

JPA 之 QueryDSL-JPA 使用指南

Querydsl-JPA 框架&#xff08;推荐&#xff09; 官网&#xff1a;传送门 参考&#xff1a; JPA整合Querydsl入门篇SpringBoot环境下QueryDSL-JPA的入门及进阶 概述及依赖、插件、生成查询实体 1.Querydsl支持代码自动完成&#xff0c;因为是纯Java API编写查询&#xff0…...

如何找回回收站删除的视频?这三种方法可以试试

在使用电脑过程中&#xff0c;我们可能会误删重要的文件&#xff0c;特别是影音文件。在这样的情况下&#xff0c;我们可以从计算机的回收站中找回已经被删除的视频。但是有时候&#xff0c;我们可能会不小心清空回收站&#xff0c;这时候就需要一些技巧来恢复回收站删除的视频…...

FPGA_边沿监测理解

一、简易频率计设计中为什么一定要获取下降沿?gate_a:实际闸门信号gate_a_stand:将实际闸门信号打一拍之后的信号gate_a_fall_s:下降沿标志信号cnt_clk_stand: Y值&#xff0c;即在实际闸门信号下&#xff0c;标准时钟信号的周期个数cnt_clk_stand_reg:保存Y值的寄存器核心问题…...

41 42Ping-Pong操作

提高电路吞吐率的结构——Ping-Pong操作 1.Ping-Pong操作原理 作用&#xff1a;为了让两个不匹配的模块进行对接&#xff0c;并且在对接的过程中让这两个模块能够同时工作&#xff0c;提高数据处理的吞吐率&#xff08;也称throughput效能&#xff09; 常见的不匹配&#xff1…...

保护你的数据安全,了解网络安全法!

网络安全法是中国自2017年6月1日起实施的一项法律&#xff0c;旨在保障网络安全和信息安全&#xff0c;维护国家安全和社会稳定。网络安全法覆盖了众多方面&#xff0c;包括网络基础设施安全、网络运营安全、个人信息保护、网络安全监管等&#xff0c;具有重要的法律意义和社会…...

什么是CatGPT-使用效果如何-

个人使用效果&#xff0c;评分优&#xff0c;足以满足教学和填表。程序媛借助CatGPT&#xff08;ChatGPT更佳&#xff09;&#xff0c;基本上可以秒杀不用此类工具的程序猿&#xff08;男&#xff09;&#xff01;&#xff01;&#xff01;问&#xff1a;为什么使用AIGC能大幅度…...

【MySQL】第17章_触发器

第17章_触发器 在实际开发中&#xff0c;我们经常会遇到这样的情况&#xff1a;有 2 个或者多个相互关联的表&#xff0c;如商品信息和库存信息分别存放在 2 个不同的数据表中&#xff0c;我们在添加一条新商品记录的时候&#xff0c;为了保证数据的完整性&#xff0c;必须同时…...

【前端】一个更底层库-React基础知识点第2篇

目录属性状态PROPSPROP VALIDATIONSTATEFORMCONTROLLED COMPONENTSMIXINCOMPONENT APICOMPONENT LIFECYCLETOP API上一篇文章也是React基础知识点&#xff0c;了解到了React是什么&#xff1f;为什么要使用React&#xff1f;还知道了JSX概述&#xff0c;JSX嵌入变量&#xff0c…...

GIT基础常用命令-1

git基础常用命令-11.git简介及配置1.1 git简介1.2 git配置config1.2.1 查看配置git config1.2.2 配置设置1.2.3 获取帮助git help2 GIT基础常用命令2.1 获取镜像仓库2.1.1 git init2.1.2 git clone2.2 本地仓库常用命令2.2.1 git status2.2.2 git add2.2.3 git diff2.2.4 git c…...

02_qml_简介

qml介绍: QML是一种描述用户界面的声明式语言。它将用户界面分解成一些更小的元素,这些元素能够结合成一个组件。QML语言描述了用户界面元素的形状和行为。用户界面能够使用JavaScript来提供修饰,或者增加更加复杂的逻辑。从这个角度来看它遵循HTML-JavaScript模式,但QML是…...

小程序项目在hbuilder里面给它打包成app

小程序项目临时有些登录需求&#xff0c;需要把&#xff08;小程序某些功能通过条件编译让它显示到app上&#xff09;小程序打包成app的话就必须需要一个打包的证书&#xff0c;证书的话就要去重新生成&#xff0c;苹果电脑可以去自动生成证书&#xff0c;平时是用windows进行开…...

linux安装pycharm

linux安装pycharm1.下载相关软件包2. 安装步骤2.1 解压文件2.2 开启命令2.4 创建快捷方式官网链接 https://www.jetbrains.com/pycharm/download/#sectionlinux 1.下载相关软件包 找到自己下载的版本下载 2. 安装步骤 2.1 解压文件 进入压缩包路径 解压文件【我指定了解…...

seata1.5.2使用从零快速上手(提供代码与安装包)

1.软件准备&#xff1a; 1.1 seata1.5.2 官网下载&#xff1a;地址:http://seata.io/zh-cn/ server源码:https://github.com/seata/seata 百度云下载&#xff08;建议&#xff09;: 百度下载 链接&#xff1a;https://pan.baidu.com/s/1eilbSI0YdmupHYI7FroTsw 提取码&…...

我的机器学习之路

名字比较大&#xff0c;就好比大麻袋&#xff0c;啥都可以往里装。 如果说人生就像旅行&#xff0c;那么通往不同风景必定是要由不同的路抵达的。 风景无穷尽&#xff0c;人生却有涯。 15年的时候也写过类似的一篇文章&#xff0c;可以叫做大数据之大路和机器学习的岔路。现在…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)

漏洞概览 漏洞名称&#xff1a;Apache Flink REST API 任意文件读取漏洞CVE编号&#xff1a;CVE-2020-17519CVSS评分&#xff1a;7.5影响版本&#xff1a;Apache Flink 1.11.0、1.11.1、1.11.2修复版本&#xff1a;≥ 1.11.3 或 ≥ 1.12.0漏洞类型&#xff1a;路径遍历&#x…...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

破解路内监管盲区:免布线低位视频桩重塑停车管理新标准

城市路内停车管理常因行道树遮挡、高位设备盲区等问题&#xff0c;导致车牌识别率低、逃费率高&#xff0c;传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法&#xff0c;正成为破局关键。该设备安装于车位侧方0.5-0.7米高度&#xff0c;直接规避树枝遮…...

多元隐函数 偏导公式

我们来推导隐函数 z z ( x , y ) z z(x, y) zz(x,y) 的偏导公式&#xff0c;给定一个隐函数关系&#xff1a; F ( x , y , z ( x , y ) ) 0 F(x, y, z(x, y)) 0 F(x,y,z(x,y))0 &#x1f9e0; 目标&#xff1a; 求 ∂ z ∂ x \frac{\partial z}{\partial x} ∂x∂z​、 …...

WEB3全栈开发——面试专业技能点P4数据库

一、mysql2 原生驱动及其连接机制 概念介绍 mysql2 是 Node.js 环境中广泛使用的 MySQL 客户端库&#xff0c;基于 mysql 库改进而来&#xff0c;具有更好的性能、Promise 支持、流式查询、二进制数据处理能力等。 主要特点&#xff1a; 支持 Promise / async-await&#xf…...