Spring Security 6.x 系列(8)—— 源码分析之配置器SecurityConfigurer接口及其分支实现

一、前言

本章主要内容是关于配置器的接口架构设计,任意找一个配置器一直往上找,就会找到配置器的顶级接口:SecurityConfigurer

查看SecurityConfigurer接口的实现类情况:

在这里插入图片描述在这里插入图片描述

AbstractHttpConfigurer 抽象类的下面可以看到所有用来配置 HttpSecurity 的配置器实现类(也是构造器)。

再通过继承关系图,看看配置器顶层的架构:

在这里插入图片描述

会发现,其中:SecurityConfigurerAdapterGlobalAuthenticationConfigurerAdapterSecurityConfigurer接口进行了实现,而WebSecurityConfigurerSecurityConfigurer接口进行了继承。

查看SecurityConfigurer源码:

源码注释:
Allows for configuring a SecurityBuilder. All SecurityConfigurer first have their init(SecurityBuilder) method invoked. After all init(SecurityBuilder) methods have been invoked, each configure(SecurityBuilder) method is invoked.
允许配置SecurityBuilder(构造器)。所有SecurityConfigurer首先调用其init(SecurityBuilderr) 方法。在调用了所有init(SecurityBuilderr) 方法之后,将调用每个configure(SecurityBuilderr) 方法。
请参阅:
AbstractConfiguredSecurityBuilder
作者:
Rob Winch
类型形参:
<O> – The object being built by the SecurityBuilder B
<O> 是被 B(继承SecurityBuilder<O>的构造器)构造出来的对象类型
<B> – The SecurityBuilder that builds objects of type O. This is also the SecurityBuilder that is being configured
<B> 是被构造对象类型O的构造器类型,也是正在配置的构造器。

特殊说明:
SecurityConfigurer 的所有实现类都是用来配置构造器的。也就是说,泛型中 O 和 B 的关系是,B 用来构造 O。而配置器的作用是配置这个构造器的,从而影响最终构造的结果。

/*** Allows for configuring a {@link SecurityBuilder}. All {@link SecurityConfigurer} first* have their {@link #init(SecurityBuilder)} method invoked. After all* {@link #init(SecurityBuilder)} methods have been invoked, each* {@link #configure(SecurityBuilder)} method is invoked.** @param <O> The object being built by the {@link SecurityBuilder} B* @param <B> The {@link SecurityBuilder} that builds objects of type O. This is also the* {@link SecurityBuilder} that is being configured.* @author Rob Winch* @see AbstractConfiguredSecurityBuilder*/
public interface SecurityConfigurer<O, B extends SecurityBuilder<O>> {/*** Initialize the {@link SecurityBuilder}. Here only shared state should be created* and modified, but not properties on the {@link SecurityBuilder} used for building* the object. This ensures that the {@link #configure(SecurityBuilder)} method uses* the correct shared objects when building. Configurers should be applied here.* * 初始化SecurityBuilder(构造器)。 这里只应该创建和修改共享状态,而不是用于构建对象的SecurityBuilder(构造器)上的属性。* 这可确保 configure(SecurityBuilder)方法在构建时使用正确的共享对象。 应在此处应用配置器。* * @param builder* @throws Exception*/void init(B builder) throws Exception;/*** Configure the {@link SecurityBuilder} by setting the necessary properties on the* * 配置SecurityBuilder(构造器)必要的属性。* * {@link SecurityBuilder}.* @param builder* @throws Exception*/void configure(B builder) throws Exception;}

下面我们分别对SecurityConfigurerAdapterGlobalAuthenticationConfigurerAdapterWebSecurityConfigurer三个分支进行源码分析。

二、SecurityConfigurerAdapter

源码注释:
A base class for SecurityConfigurer that allows subclasses to only implement the methods they are interested in. It also provides a mechanism for using the SecurityConfigurer and when done gaining access to the SecurityBuilder that is being configured.
SecurityConfigurer的基类,它允许子类仅实现它们感兴趣的方法。。它还提供了使用 SecurityConfigurer以及完成后获取正在配置的SecurityBuilder(构造器)的访问权限的机制。
作者:
Rob Winch, Wallace Wadge
类型形参:
<O> – The Object being built by B
<O> 是被 B 构造出来的对象类型
<B> – The Builder that is building O and is configured by SecurityConfigurerAdapter
<B> 是被构造对象类型O的构造器,同时也是此 SecurityConfigurerAdapter正在配置的对象。

/*** A base class for {@link SecurityConfigurer} that allows subclasses to only implement* the methods they are interested in. It also provides a mechanism for using the* {@link SecurityConfigurer} and when done gaining access to the {@link SecurityBuilder}* that is being configured.** @param <O> The Object being built by B* @param <B> The Builder that is building O and is configured by* {@link SecurityConfigurerAdapter}* @author Rob Winch* @author Wallace Wadge*/
public abstract class SecurityConfigurerAdapter<O, B extends SecurityBuilder<O>> implements SecurityConfigurer<O, B> {private B securityBuilder;private CompositeObjectPostProcessor objectPostProcessor = new CompositeObjectPostProcessor();@Overridepublic void init(B builder) throws Exception {}@Overridepublic void configure(B builder) throws Exception {}/*** Return the {@link SecurityBuilder} when done using the {@link SecurityConfigurer}.* This is useful for method chaining.* @return the {@link SecurityBuilder} for further customizations* @deprecated For removal in 7.0. Use the lambda based configuration instead.*/@Deprecated(since = "6.1", forRemoval = true)public B and() {return getBuilder();}/*** Gets the {@link SecurityBuilder}. Cannot be null.* @return the {@link SecurityBuilder}* @throws IllegalStateException if {@link SecurityBuilder} is null*/protected final B getBuilder() {Assert.state(this.securityBuilder != null, "securityBuilder cannot be null");return this.securityBuilder;}/*** Performs post processing of an object. The default is to delegate to the* {@link ObjectPostProcessor}.* @param object the Object to post process* @return the possibly modified Object to use*/@SuppressWarnings("unchecked")protected <T> T postProcess(T object) {return (T) this.objectPostProcessor.postProcess(object);}/*** Adds an {@link ObjectPostProcessor} to be used for this* {@link SecurityConfigurerAdapter}. The default implementation does nothing to the* object.* @param objectPostProcessor the {@link ObjectPostProcessor} to use*/public void addObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {this.objectPostProcessor.addObjectPostProcessor(objectPostProcessor);}/*** Sets the {@link SecurityBuilder} to be used. This is automatically set when using* {@link AbstractConfiguredSecurityBuilder#apply(SecurityConfigurerAdapter)}* @param builder the {@link SecurityBuilder} to set*/public void setBuilder(B builder) {this.securityBuilder = builder;}/*** An {@link ObjectPostProcessor} that delegates work to numerous* {@link ObjectPostProcessor} implementations.** @author Rob Winch*/private static final class CompositeObjectPostProcessor implements ObjectPostProcessor<Object> {private List<ObjectPostProcessor<?>> postProcessors = new ArrayList<>();@Override@SuppressWarnings({ "rawtypes", "unchecked" })public Object postProcess(Object object) {for (ObjectPostProcessor opp : this.postProcessors) {Class<?> oppClass = opp.getClass();Class<?> oppType = GenericTypeResolver.resolveTypeArgument(oppClass, ObjectPostProcessor.class);if (oppType == null || oppType.isAssignableFrom(object.getClass())) {object = opp.postProcess(object);}}return object;}/*** Adds an {@link ObjectPostProcessor} to use* @param objectPostProcessor the {@link ObjectPostProcessor} to add* @return true if the {@link ObjectPostProcessor} was added, else false*/private boolean addObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {boolean result = this.postProcessors.add(objectPostProcessor);this.postProcessors.sort(AnnotationAwareOrderComparator.INSTANCE);return result;}}}

内容很简单:

  • 有一个内部类CompositeObjectPostProcessor:复合后置处理器对象类

  • 定义了两个成员变量:

    • 将要配置的构造器 securityBuilder
    • 复合后置处理器 objectPostProcessor
  • 从接口中实现的方法和自己新加的几个方法

    • initconfigure 是实现接口的方法
    • andgetBuilderpostProcessaddObjectPostProcessorsetBuilder 方法是自己加的

2.1 允许子类只实现他们感兴趣的方法

在源码中可以看到,所有的方法都有方法体,包括对接口方法的实现(虽然是空方法体)。所以继承 SecurityConfigurerAdapter 的配置器可以根据自己的需求实现覆盖)自己感兴趣的方法。

可以自己实现 init ,如果自己不需要初始化,也可以不实现,在构造器调用其 init 方法时什么也不做。

2.2 setBuilder 方法

这个方法有点特别,所以单独说一下,方法内容很简单,就是设置配置器的成员变量private B securityBuilder即:构造器),但是官网又这样一句注释:

Sets the SecurityBuilder to be used.
This is automatically set when using AbstractConfiguredSecurityBuilder.apply(SecurityConfigurerAdapter)

第一句很好理解:这个方法是来设置要使用的构造器(private B securityBuilder,其B extends SecurityBuilder<O>)。

第二句就是当 AbstractConfiguredSecurityBuilder.apply(SecurityConfigurerAdapter) 调用时被自动设置。

回顾上篇中的4.4.7章节:

/*** Applies a {@link SecurityConfigurerAdapter} to this {@link SecurityBuilder} and* invokes {@link SecurityConfigurerAdapter#setBuilder(SecurityBuilder)}.* @param configurer* @return the {@link SecurityConfigurerAdapter} for further customizations* @throws Exception*/
@SuppressWarnings("unchecked")
public <C extends SecurityConfigurerAdapter<O, B>> C apply(C configurer) throws Exception {configurer.addObjectPostProcessor(this.objectPostProcessor);configurer.setBuilder((B) this);add(configurer);return configurer;
}

可以看出,configurer在被调用之前是不知道要配置哪个构造器的。在构造器调用 apply 方法时才真正设置配置器的成员变量(即:构造器)。所以官方注释才说 setBuilder 方法时自动调用的,我们不能手动去设置。

只有构造器(B) this应用了这个配置器configurer,这个配置器configurer才会绑定上这个构造器(B) this

2.3 and 方法

and() 方法提供了一种使用SecurityConfigurer以及完成后获取正在配置的SecurityBuilder(构造器)的访问权限的机制。

有必要说一下为什么是正在配置,因为在这个时候还没有对构造器(private B securityBuilder )进行配置。

在上篇文章中讲解Builder设计模式时,提到过构造器的构造时机在调用构造器的 build 方法,在AbstractConfiguredSecurityBuilder#doBuild方法中加入了构造生命周期控制,在里面才开始调用各个配置器的 init 方法和 configure 方法。所以这里获取到的时正在配置的构造器对象。

在构造器的构造过程中利用配置器进行配置,从而影响最终构造的结果。

2.4 复合后置处理对象

这个内部类对象很简单,看一下内部类的内容就明白了:它维护的是一个 List 集合

private List<ObjectPostProcessor<?>> postProcessors = new ArrayList<>();

因此称之为:复合后置处理对象(CompositeObjectPostProcessor),就是里面有多个。

2.5 DEBUG 参数跟踪

AbstractConfiguredSecurityBuilder#apply

在这里插入图片描述
SecurityConfigurerAdapter#setBuilder

在这里插入图片描述

由上可知: SecurityConfigurerAdapter中设置的构造器为HttpSecurity

三、GlobalAuthenticationConfigurerAdapter

这个类的类名说明它是一个全局配置相关的类。

/*** A {@link SecurityConfigurer} that can be exposed as a bean to configure the global* {@link AuthenticationManagerBuilder}. Beans of this type are automatically used by* {@link AuthenticationConfiguration} to configure the global* {@link AuthenticationManagerBuilder}.** @author Rob Winch* @since 5.0*/
@Order(100)
public abstract class GlobalAuthenticationConfigurerAdapterimplements SecurityConfigurer<AuthenticationManager, AuthenticationManagerBuilder> {@Overridepublic void init(AuthenticationManagerBuilder auth) throws Exception {}@Overridepublic void configure(AuthenticationManagerBuilder auth) throws Exception {}}

从源码可以看出它实现 SecurityConfigurer 接口,没有具体的实现内容,只是对构造器和构造器将要构造的对象做了限制:

  • 将要配置的构造器:AuthenticationManagerBuilder

    可以作为bean公开以配置全局构造器AuthenticationManagerBuilder

  • 将要构造的对象:AuthenticationManager

    将被构造器构造出最终目的类型AuthenticationManager

四、WebSecurityConfigurer

/*** Allows customization to the {@link WebSecurity}. In most instances users will use* {@link EnableWebSecurity} and create a {@link Configuration} that exposes a* {@link SecurityFilterChain} bean. This will automatically be applied to the* {@link WebSecurity} by the {@link EnableWebSecurity} annotation.** @author Rob Winch* @since 3.2* @see SecurityFilterChain*/
public interface WebSecurityConfigurer<T extends SecurityBuilder<Filter>> extends SecurityConfigurer<Filter, T> {}

该接口继承SecurityConfigurer接口,从源码中可以看出,它没有定义自己的方法,所有的方法都是从父接口继承,那么它的作用还有配置SecurityBuilder(构造器),但是它对类型做了约束:

  • WebSecurityConfigurer 的泛型为 T

    T继承了SecurityBuilder,所以T表示是一个对象构造器

  • SecurityBuilder的泛型为Filter

    表示 SecurityBuilder 将要构造的对象是一个 javax.servet.Filter,也就是说,它约束了T,说明T的作用是构造Filter

  • 将要传入父接口SecurityConfigurer的两个泛型:FilterT

    WebSecurityConfigurer 继承 SecurityConfigurer,从这里可以看出,对SecurityConfigurer做了约束,目前只有T还没有指定具体的类型,至于最终使用什么类型的构造器由实现类或者子接口指定。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/196824.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

idea类和方法模版

类模版 修改目标位置 class #if (${PACKAGE_NAME} && ${PACKAGE_NAME} ! "")package ${PACKAGE_NAME};#end #parse("File Header.java")/*** ${Description}* author whc ${YEAR}/${MONTH}/${DAY}* version v1.0 */public class ${NAME} { }inte…

【网络安全】虚假IP地址攻击如何防范?

在当今的网络时代&#xff0c;虚假IP地址攻击已成为一种新型的网络攻击方式&#xff0c;给网络安全带来了极大的威胁。那么&#xff0c;什么是虚假IP地址攻击&#xff1f;又如何进行溯源和防范呢&#xff1f;本文将为您揭开这一神秘面纱。 一、虚假IP地址攻击概述 虚假IP地址攻…

[python]离线加载fetch_20newsgroups数据集

首先手动下载这个数据包 http://qwone.com/~jason/20Newsgroups/20news-bydate.tar.gz 下载这个文件后和脚本放一起就行&#xff0c;然后 打开twenty_newsgroups.py文件&#xff08;在fetch_20newsgroups函数名上&#xff0c;右键转到定义即可找到&#xff09; 之后运行代码即…

羊大师教你如何有效应对冬季流感,保护自己与家人

羊大师教你如何有效应对冬季流感&#xff0c;保护自己与家人 随着冬季的临近&#xff0c;流感病毒将再次蔓延。如何预防冬季流感来袭&#xff0c;成为了许多人关注的话题。幸运的是&#xff0c;我们可以采取一系列的预防措施来保护自己和家人&#xff0c;避免被流感侵袭。下面…

【Altium designer 20】

Altium designer 20 1. Altium designer 201.1 原理图库1.1.1 上划岗 在字母前面加\在加字母1.1.2 自定义快捷键1.1.3 对齐1.1.4 在原有的电路图中使用封装1.1.5 利用excel创建IC类元件库1.1.6 现有原理图库分类以及调用1.1.7 现有原理图库中自动生成原理图库 1.2 绘制原理图1.…

【初阶解法-数据结构】包含min函数的栈(代码+图示)

【数据结构】刷题-包含min函数的栈(代码图示)-初阶解法 文章目录 【数据结构】刷题-包含min函数的栈(代码图示)-初阶解法题目提炼题目要求分析题目总结思路代码时间/空间复杂度进阶版 题目 定义栈的数据结构&#xff0c;请在该类型中实现一个能够得到栈中所含最小元素的 min 函…

Ubuntu22.04 交叉编译mp4V2 for Rv1106

一、配置工具链环境 sudo vim ~/.bashrc在文件最后添加 export PATH$PATH:/opt/arm-rockchip830-linux-uclibcgnueabihf/bin 保存&#xff0c;重启机器 二、下载mp4v2 下载路径&#xff1a;MP4v2 | mp4v2 三、修改CMakeLists.txt 四、执行编译 mkdir build cd buildcmak…

羊大师教你如何在冬天运动,然后悄悄惊艳所有人

羊大师教你如何在冬天运动&#xff0c;然后悄悄惊艳所有人 寒冷的冬季&#xff0c;寂静的清晨&#xff0c;你是否也曾感到在冰冷的天气中进行锻炼是一件非常困难的事情&#xff1f;但是&#xff0c;现在请跟随小编羊大师一起来探索冬季秘密运动&#xff0c;让你在春节惊艳众人…

人工智能_机器学习060_核函数对应数学公式_数据空间错位分割_简单介绍_以及核函数总结---人工智能工作笔记0100

我们之前做的都是线性分类问题,那么需要一根线来分割类别,但是,如果出现了,环形数据,我们知道,在二维中我们就无法分割了,那么有没有什么办法分割呢? 实际上是有的,可以看到,我们可以把数据进行升维,可以看到,如果把数据升高到2维度以上,可以看到,神奇的一幕出现了,这个时候,因…

【Linux】进程控制--进程创建/进程终止/进程等待/进程程序替换/简易shell实现

文章目录 一、进程创建1.fork函数2.fork函数返回值3.写时拷贝4.fork常规用法5.fork调用失败的原因 二、进程终止1.进程退出码2.进程退出场景3.进程常见退出方法 三、进程等待1.为什么要进行进程等待2.如何进行进程等待1.wait方法2.waitpid方法3.获取子进程status4.进程的阻塞等…

价差后的几种方向,澳福如何操作才能盈利

在价差出现时&#xff0c;澳福认为会出现以下几种方向。 昂贵资产的贬值和便宜资产的平行升值。昂贵的资产贬值&#xff0c;而便宜的资产保持不变。昂贵资产的贬值和便宜资产的平行贬值&#xff0c;但昂贵资产的贬值速度更快&#xff0c;超过便宜资产。更贵的一对的进一步升值和…

7. 系统信息与系统资源

7. 系统信息与系统资源 1. 系统信息1.1 系统标识 uname()1.2 sysinfo()1.3 gethostname()1.4 sysconf() 2. 时间、日期2.1 Linux 系统中的时间2.1.1 Linux 怎么记录时间2.1.2 jiffies 的引入 2.2 获取时间 time/gettimeofday2.2.1 time()2.2.2 gettimeofday() 2.3 时间转换函数…

登录校验过滤器

会话技术 JWT令牌 过滤器Filter 拦截器 interceptor cookise package com.it.controller;import com.it.pojo.Result; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.Re…

Android wifi连接和获取IP分析

wifi 连接&获取IP 流程图 代码流程分析 一、关联阶段 1. WifiSettings.submit – > WifiManager WifiSettings 干的事情比较简单&#xff0c;当在dialog完成ssid 以及密码填充后&#xff0c;直接call WifiManager save 即可WifiManager 收到Save 之后&#xff0c;就开…

新的 BLUFFS 攻击导致蓝牙连接不再私密

蓝牙是一种连接我们设备的低功耗无线技术&#xff0c;有一个新的漏洞需要解决。 中间的攻击者可以使用新的 BLUFFS 攻击轻松窥探您的通信。 法国研究中心 EURECOM 的研究员 Daniele Antonioli 演示了六种新颖的攻击&#xff0c;这些攻击被定义为 BLUFFS&#xff08;蓝牙转发和…

【Java】文件I/O-文件内容操作-输入输出流-Reader/Writer/InputStream/OutputStream四种流

导读 在文件I/O这一节的知识里&#xff0c;对文件的操作主要分为两大类&#xff1a; ☑️针对文件系统进行的操作 ☑️针对文件内容进行的操作 上文已经讲了针对文件系统即File类的操作&#xff0c;这篇文章里博主就来带了解针对文件内容的操作&#xff0c;即输入输出流&am…

Open Inventor 2023.2.1 Crack

Fixed Bugs List 2023.2 2023.2.1 Open Inventor 2023.2.1 MeshViz #OIV-4824 Crash in MeshViz PbNonLinearDataMapping::computeColor Cache #OIV-4867 SoText3 : Texture read access violation – CAS-44904 Core #OIV-4725 Invalid displayed PoCircle color…

MySQL笔记-第06章_多表查询

视频链接&#xff1a;【MySQL数据库入门到大牛&#xff0c;mysql安装到优化&#xff0c;百科全书级&#xff0c;全网天花板】 文章目录 第06章_多表查询1. 一个案例引发的多表连接1.1 案例说明1.2 笛卡尔积&#xff08;或交叉连接&#xff09;的理解1.3 案例分析与问题解决 2. …

C#网络编程UDP程序设计(UdpClient类)

目录 一、UdpClient类 二、示例 1.源码 &#xff08;1&#xff09;Client &#xff08;2&#xff09;Server 2.生成 &#xff08;1&#xff09;先启动服务器&#xff0c;发送广播信息 &#xff08;2&#xff09;再开启客户端接听 UDP是user datagram protocol的简称&a…

BFS求树的宽度——结合数组建树思想算距离

二叉树最大宽度 https://leetcode.cn/problems/maximum-width-of-binary-tree/description/ 1、考虑树的宽度一定是在一层上的所以进行BFS&#xff0c;树的BFS不建议直接使用队列&#xff0c;每次add/offer然后poll/remove&#xff0c;这样子层级关系不好显示。我们可以定义…