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.rhkb.cn/news/209961.html

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

相关文章

利用异或、取反、自增bypass_webshell_waf

目录 引言 利用异或 介绍 eval与assert 蚁剑连接 进阶题目 利用取反 利用自增 引言 有这样一个waf用于防御我们上传的文件&#xff1a; function fun($var): bool{$blacklist ["\$_", "eval","copy" ,"assert","usort…

pip的基本命令和使用

pip 简介 pip是Python官方的包管理器&#xff0c;可以方便地安装、升级和卸载Python包。 pip 常用命令 显示版本和路径 pip --version获取帮助 pip --help升级pip和升级包 pip install --upgrade pip # Linux/macOS pip install -U pip # windowspip install…

每日一练【盛最多水的容器】

一、题目描述 11. 盛最多水的容器 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&…

Qt Creator使用Heob检测内存泄漏

开发环境&#xff1a;win10 qt5.12.0 编译环境:MinGW 使用内存泄漏排查工具heob步骤如下: 第一步:下载heob.exe--注&#xff1a;我本机仅有heob.exe还不行&#xff0c;提示如下 所以需要下载heob和Dwarfstack&#xff0c;然后把他们放到同级目录下&#xff0c;我已经下载并且…

Mybatis中的设计模式

Mybatis中的设计模式 Mybatis中使用了大量的设计模式。 以下列举一些看源码时&#xff0c;觉得还不错的用法&#xff1a; 创建型模式 工厂方法模式 DataSourceFactory 通过不同的子类工厂&#xff0c;实例化不同的DataSource TransactionFactory 通过不同的工厂&#xff…

js moment时间范围拿到中间间隔时间

2023.11.27今天我学习了如何对只返回的开始时间和结束时间做处理&#xff0c;比如后端返回了&#xff1a; [time:{start:202301,end:202311}] 我们需要把中间的间隔渲染出来。 [202301,202302,202303,202304,202305,202306,202307,202308,202309,202310,202311] 利用moment…

01 高等数学.武忠祥.0基础

第一章 函数与极限 01映射与函数 02 函数概念 对应法则 定义域 常见函数 函数的几种特性 周期函数不一定有最小周期。 涉及额外与复习 存在与任意的关系

Star 10.4k!推荐一款国产跨平台、轻量级的文本编辑器,内置代码对比功能

notepad 相信大家从学习这一行就开始用了&#xff0c;它是开发者/互联网行业的上班族使用率最高的一款轻量级文本编辑器。但是它只能在Windows上进行使用&#xff0c;而且正常来说是收费的&#xff08;虽然用的是pj的&#xff09;。 对于想在MacOS、Linux上想使用&#xff0c;…

关于使用百度开发者平台处理语音朗读问题排查

错误信息&#xff1a;"convert_offline": false, "err_detail": "16: Open api characters limit reach 需要领取完 识别和合成都要有

Clean 架构下的现代 Android 架构指南

Clean 架构下的现代 Android 架构指南 Clean 架构是 Uncle Bob 提出的一种软件架构&#xff0c;Bob 大叔同时也是 SOLID 原则的命名者。 Clean 架构图如下&#xff1a; 这张图描述的是整个软件系统的架构&#xff0c;而不是单体软件&#xff0c;其中至少包括服务端以及客户端…

【Java】类和对象之超级详细的总结!!!

文章目录 前言1. 什么是面向对象&#xff1f;1.2面向过程和面向对象 2.类的定义和使用2.1什么是类&#xff1f;2.2类的定义格式2.3类的实例化2.3.1什么是实例化2.3.2类和对象的说明 3.this引用3.1为什么会有this3.2this的含义与性质3.3this的特性 4.构造方法4.1构造方法的概念4…

ElasticSearch学习笔记(一)

计算机软件的学习&#xff0c;最重要的是举一反三&#xff0c;只要大胆尝试&#xff0c;认真验证自己的想法就能收到事办功倍的效果。在开始之前可以看看别人的教程做个快速的入门&#xff0c;然后去官方网站看看官方的教程&#xff0c;有中文教程固然是好&#xff0c;没有中文…

dcat admin日志扩展 dcat-log-viewer 遇到的问题记录

扩展地址&#xff1a; https://github.com/duolabmeng6/dcat-log-viewer 问题描述&#xff1a; 使用很简单&#xff0c;直接安装扩展包&#xff0c;开启扩展就可以了&#xff0c;会自动生成菜单。 之前在别的系统用过&#xff0c;没问题&#xff0c;今天在一个新的系统用的时…

【网络奇缘】- 计算机网络|分层结构|深入探索TCP/IP模型|5层参考模型

​ &#x1f308;个人主页: Aileen_0v0&#x1f525;系列专栏: 一见倾心,再见倾城 --- 计算机网络~&#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 OSI参考模型与TCP/IP参考模型相同点 OSI参考模型与TCP/IP参考模型不同点 面向连接三阶段&#xff08…

单片机系统

我们来看单片机 的例子&#xff0c;读者可能会担心单片机&#xff08;又称MCU&#xff0c;或微控制器&#xff09; 过于专业而无法理解。完全没必要&#xff01;在这里我们仅借它谈论一下有关时间的话题&#xff0c;顺带提一下单片机系统的概念。 单片机顾名思义是集成到一个芯…

基于SSM框架的网上书店系统

基于SSM框架的网上书店系统 文章目录 基于SSM框架的网上书店系统 一.引言二.系统设计三.技术架构四.功能实现五.界面展示六.源码获取 一.引言 随着互联网的普及和电子商务的快速发展&#xff0c;网上书店系统成为了现代人购买图书的主要方式之一。网上书店系统不仅提供了便捷的…

Redis队列stream,Redis多线程详解

Redis 目前最新版本为 Redis-6.2.6 &#xff0c;会以 CentOS7 下 Redis-6.2.4 版本进行讲解。 下载地址&#xff1a; https://redis.io/download 安装运行 Redis 很简单&#xff0c;在 Linux 下执行上面的 4 条命令即可 &#xff0c;同时前面的 课程已经有完整的视…

【UGUI】实现背包的常用操作

1. 添加物品 首先&#xff0c;你需要一个包含物品信息的类&#xff0c;比如 InventoryItem&#xff1a; using UnityEngine;[CreateAssetMenu(fileName "NewInventoryItem", menuName "Inventory/Item")] public class InventoryItem : ScriptableObje…

Postman:专业API测试工具,提升Mac用户体验

如果你是一名开发人员或测试工程师&#xff0c;那么你一定知道Postman。这是一个广泛使用的API测试工具&#xff0c;适用于Windows、Mac和Linux系统。今天&#xff0c;我们要重点介绍Postman的Mac版本&#xff0c;以及为什么它是你进行API测试的理想选择。 一、强大的功能和易…

第3章 表、栈和队列

3.4 队列ADT 像栈一样&#xff0c;队列(queue)也是表。然而&#xff0c;使用队列时插入在一端进行而删除则在另一端 进行。 3.4.1 队列模型 队列的基本操作是Enqueue(入队)一它是在表的末端(叫作队尾(rear))插入一个元素&#xff0c;还有Dequeue(出队)——它是删除(或返回)在…