6.深入理解SecurityConfigurer

news2024/11/15 21:37:20

深入理解SecurityConfigurer

一、SecurityConfigurer

  SecurityConfigurer 在 Spring Security 中是一个非常重要的角色。在前面的内容中曾经多次提到过,
Spring Security 过滤器链中的每一个过滤器,都是通过 xxxConfigurer 来进行配置的,而这些
xxxConfigurer 实际上都是 SecurityConfigurer 的实现。所以我们也需要对 SecurityConfigurer 理解清楚.

//  O(DefaultSecurityFilterChain)  B(HttpSecurity)
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.
	 * @param builder
	 * @throws Exception
	 */
	void init(B builder) throws Exception;

	/**
	 * Configure the {@link SecurityBuilder} by setting the necessary properties on the
	 * {@link SecurityBuilder}.
	 * @param builder
	 * @throws Exception
	 */
	void configure(B builder) throws Exception;

}

在init方法和configure方法中的形参都是SecurityBuilder类型,而SecurityBuilder是用来构建过滤器链
的【DefaultSecurityFilterChainProxy】
SecurityConfigurer的实现当然很多。image.png

具体的Configurer实现我们可以先不关注,我需要了解的SecurityConfigurer的核心实现有三个

image.png

二、SecurityConfigurerAdapter

  SecurityConfigurerAdapter 实现了 SecurityConfigurer 接口,我们所使用的大部分的xxxConfigurer 也都是 SecurityConfigurerAdapter 的子类。
  SecurityConfigurerAdapter 在 SecurityConfigurer 的基础上,还扩展出来了几个非常好用的方法

image.png

  1. CompositeObjectPostProcessor ()
    首先一开始声明了一个 CompositeObjectPostProcessor 实例,CompositeObjectPostProcessor
    是 ObjectPostProcessor 的一个实现,ObjectPostProcessor 本身是一个后置处理器,该后置处
    理器默认有两个实现,AutowireBeanFactoryObjectPostProcessor 和
    CompositeObjectPostProcessor。其中 AutowireBeanFactoryObjectPostProcessor 主要是利用
    了 AutowireCapableBeanFactory 对 Bean 进行手动注册,因为在 Spring Security 中,很多对象
    都是手动 new 出来的,这些 new 出来的对象和容器没有任何关系,利用AutowireCapableBeanFactory 可以将这些手动 new 出来的对象注入到容器中,而AutowireBeanFactoryObjectPostProcessor 的主要作用就是完成这件事;CompositeObjectPostProcessor 则是一个复合的对象处理器,里边维护了一个 List 集合,这个List 集合中,大部分情况下只存储一条数据,那就是AutowireBeanFactoryObjectPostProcessor ,用来完成对象注入到容器的操作,如果用户自己手动调用了 addObjectPostProcessor 方法,那么 CompositeObjectPostProcessor 集合中维护的数据就会多出来一条,CompositeObjectPostProcessor #postProcess 方法中,会遍历集合中的所有 ObjectPostProcessor,挨个调用其 postProcess 方法对对象进行后置处理。
  2. and (),
    该方法返回值是一个 securityBuilder,securityBuilder 实际上就是 HttpSecurity,我们在HttpSecurity 中去配置不同的过滤器时,可以使用 and 方法进行链式配置,就是因为这里定义了
    and 方法并返回了 securityBuilder 实例

这便是 SecurityConfigurerAdapter 的主要功能,后面大部分的 xxxConfigurer 都是基于此类来实
现的

三、GlobalAuthenticationConfigurerAdapter

  GlobalAuthenticationConfigurerAdapter 看名字就知道是一个跟全局配置有关的东西,它本身实
现了 SecurityConfigurerAdapter 接口,但是并未对方法做具体的实现,只是将泛型具体化了

@Order(100)
public abstract class GlobalAuthenticationConfigurerAdapter
		implements SecurityConfigurer<AuthenticationManager, AuthenticationManagerBuilder> {

	@Override
	public void init(AuthenticationManagerBuilder auth) throws Exception {
	}

	@Override
	public void configure(AuthenticationManagerBuilder auth) throws Exception {
	}

}

  可以看到,SecurityConfigurer 中的泛型,现在明确成了 AuthenticationManager 和
AuthenticationManagerBuilder。所以 GlobalAuthenticationConfigurerAdapter 的实现类将来主要
是和配置 AuthenticationManager 有关。当然也包括默认的用户名密码也是由它的实现类来进行配置
的。
  我们在 Spring Security 中使用的 AuthenticationManager 其实可以分为两种,一种是局部的,另一种
是全局的,这里主要是全局的配置

四、WebSecurityConfigurer

  还有一个实现类就是 WebSecurityConfigurer,这个可能有的小伙伴比较陌生,其实他就是我们天
天用的 WebSecurityConfigurerAdapter 的父接口。
  所以 WebSecurityConfigurer 的作用就很明确了,用户扩展用户自定义的配置

image.png

五、SecurityConfigurerAdapter

SecurityConfigurerAdapter 的实现主要也是三大类:

  • UserDetailsAwareConfigurer
  • AbstractHttpConfigurer
  • LdapAuthenticationProviderConfigurer

考虑到 LDAP 现在使用很少,所以这里我来和大家重点介绍下前两个。

1.UserDetailsAwareConfigurer

  这个配置类看名字大概就知道这是用来配置用户类的。

image.png

对应的实现类的结构图

image.png

UserDetailsAwareConfigurer接口

public abstract class UserDetailsAwareConfigurer<B extends ProviderManagerBuilder<B>, U extends UserDetailsService>
		extends SecurityConfigurerAdapter<AuthenticationManager, B> {

	/**
     * 返回的是UserDetailsService 接口的实现
	 * Gets the {@link UserDetailsService} or null if it is not available
	 * @return the {@link UserDetailsService} or null if it is not available
	 */
	public abstract U getUserDetailsService();

}

  通过定义我们可以看到泛型U必须是UserDetailsService接口的实现,也就是
getUserDetailsService()方法返回的肯定是UserDetailsService接口的实现,还有通过泛型B及继承
SecurityConfigurerAdapter来看会构建一个AuthenticationManager对象

AbstractDaoAuthenticationConfigurer

接下来我们再看下UserDetailsAwareConfigurer下的一个抽象类
AbstractDaoAuthenticationConfigurer
在类的头部声明了一堆的泛型,继承自UserDetailsAwareConfigurer

public abstract class AbstractDaoAuthenticationConfigurer<B extends ProviderManagerBuilder<B>, C extends AbstractDaoAuthenticationConfigurer<B, C, U>, U extends UserDetailsService>
		extends UserDetailsAwareConfigurer<B, U> {
// 声明了一个 provider
	private DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
// 声明了一个 userDetailsService 的泛型属性

	private final U userDetailsService;

	/**
	 * Creates a new instance
构造器 传递的对象可以是UserDetailsService或者UserDetailsPasswordService
	 * @param userDetailsService
	 */
	AbstractDaoAuthenticationConfigurer(U userDetailsService) {
		this.userDetailsService = userDetailsService;
		this.provider.setUserDetailsService(userDetailsService);
		if (userDetailsService instanceof UserDetailsPasswordService) {
			this.provider.setUserDetailsPasswordService((UserDetailsPasswordService) userDetailsService);
		}
	}

	/**
	 * Adds an {@link ObjectPostProcessor} for this class.
添加了一个ObjectPostProcessor 后置处理器
	 * @param objectPostProcessor
	 * @return the {@link AbstractDaoAuthenticationConfigurer} for further customizations
	 */
	@SuppressWarnings("unchecked")
	public C withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
		addObjectPostProcessor(objectPostProcessor);
		return (C) this;
	}

	/**
添加密码编码器 加密
	 * Allows specifying the {@link PasswordEncoder} to use with the
	 * {@link DaoAuthenticationProvider}. The default is to use plain text.
	 * @param passwordEncoder The {@link PasswordEncoder} to use.
	 * @return the {@link AbstractDaoAuthenticationConfigurer} for further customizations
	 */
	@SuppressWarnings("unchecked")
	public C passwordEncoder(PasswordEncoder passwordEncoder) {
		this.provider.setPasswordEncoder(passwordEncoder);
		return (C) this;
	}

	public C userDetailsPasswordManager(UserDetailsPasswordService passwordManager) {
		this.provider.setUserDetailsPasswordService(passwordManager);
		return (C) this;
	}

	@Override
	public void configure(B builder) throws Exception {
// 调用后置处理器 将provider添加到SpringIoC容器中
		this.provider = postProcess(this.provider);
// 将provider添加到builder对象中
		builder.authenticationProvider(this.provider);
	}

	/**
	 * Gets the {@link UserDetailsService} that is used with the
	 * {@link DaoAuthenticationProvider}  重写父类的方法
	 * @return the {@link UserDetailsService} that is used with the
	 * {@link DaoAuthenticationProvider}
	 */
	@Override
	public U getUserDetailsService() {
		return this.userDetailsService;
	}

}

UserDetailsServiceConfigurer

  这个类就比较简单,扩展了AbstractDaoAuthenticationConfigurer中的configure方法,在
configure 方法执行之前加入了 initUserDetailsService 方法,以方便开发展按照自己的方式去初始化
UserDetailsService。不过这里的 initUserDetailsService 方法是空方法

public class UserDetailsServiceConfigurer<B extends ProviderManagerBuilder<B>, C extends UserDetailsServiceConfigurer<B, C, U>, U extends UserDetailsService>
		extends AbstractDaoAuthenticationConfigurer<B, C, U> {

	/**
	 * Creates a new instance
	 * @param userDetailsService the {@link UserDetailsService} that should be used
	 */
	public UserDetailsServiceConfigurer(U userDetailsService) {
		super(userDetailsService);
	}

	@Override
	public void configure(B builder) throws Exception {
		initUserDetailsService();
		super.configure(builder);
	}

	/**
	 * Allows subclasses to initialize the {@link UserDetailsService}. For example, it
	 * might add users, initialize schema, etc.
	 */
	protected void initUserDetailsService() throws Exception {
	}

}

UserDetailsManagerConfigurer

  UserDetailsManagerConfigurer 中实现了 UserDetailsServiceConfigurer 中定义的
initUserDetailsService 方法,具体的实现逻辑就是将 UserDetailsBuilder 所构建出来的 UserDetails
以及提前准备好的 UserDetails 中的用户存储到 UserDetailsService 中。
  该类同时添加了 withUser 方法用来添加用户,同时还增加了一个 UserDetailsBuilder 用来构建用
户,这些逻辑都比较简单,小伙伴们可以自行查看。

JdbcUserDetailsManagerConfigurer

  JdbcUserDetailsManagerConfigurer 在父类的基础上补充了 DataSource 对象,同时还提供了相应
的数据库查询方法

InMemoryUserDetailsManagerConfigurer

InMemoryUserDetailsManagerConfigurer 在父类的基础上重写了构造方法,将父类中的
UserDetailsService 实例定义为 InMemoryUserDetailsManager

public class InMemoryUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>>
		extends UserDetailsManagerConfigurer<B, InMemoryUserDetailsManagerConfigurer<B>> {

	/**
	 * Creates a new instance
	 */
	public InMemoryUserDetailsManagerConfigurer() {
		super(new InMemoryUserDetailsManager(new ArrayList<>()));
	}

}

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

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

相关文章

文件跳过回收站删除了常见原因|找回方法

演示机型&#xff1a;技嘉 H310M HD22.0系统版本&#xff1a;Windows 10 专业版软件版本&#xff1a;云骑士数据恢复软件3.21.0.92你有没有遇到文件跳过回收站而直接删除的情况&#xff1f;如果有的话&#xff0c;你是知道是什么原因吗&#xff1f;文件跳过回收站删除了怎么办&…

【JavaScript速成之路】JavaScript数组

&#x1f4c3;个人主页&#xff1a;「小杨」的csdn博客 &#x1f525;系列专栏&#xff1a;【JavaScript速成之路】 &#x1f433;希望大家多多支持&#x1f970;一起进步呀&#xff01; 文章目录前言1&#xff0c;初识数组1.1&#xff0c;数组1.2&#xff0c;创建数组1.3&…

SCI期刊收不收费也有门道,你知道吗?

什么是OA期刊? OA期刊是在互联网上在线出版的学术刊物&#xff0c;英文全称是OpenAccess Journal&#xff0c;中文译为“开放存取期刊”。OA期刊不同于传统的学术期刊如《自然》、《科学》等&#xff0c;采取的是向读者收费的运营模式&#xff0c;读者只有付费订阅&#xff0…

【MySQL】表的数据处理

哈喽&#xff0c;大家好&#xff01;我是保护小周ღ&#xff0c;本期为大家带来的是 MySQL 数据表中数据的基本处理的操作&#xff0c;数据表的增删改查&#xff0c;更多相关知识敬请期待&#xff1a;保护小周ღ *★,*:.☆(&#xffe3;▽&#xffe3;)/$:*.★*一、 添加数据&a…

极简RSS订阅器Miniflux

什么是 Miniflux &#xff1f; Miniflux 是一个极简主义的 RSS 阅读器。它简单、快速、轻便且非常易于使用。Miniflux 是静态编译的单个二进制文件&#xff0c;没有使用任何复杂的框架&#xff0c;也没有外部依赖&#xff0c;简单、快速、轻巧且超级容易安装。支持 Atom、RSS 1…

Docker(五)--Docker网络--源生网络、自定义网络

文章目录一、源生网络1.docker 的网桥---bridge2.host网络模型3.none 网络模型二、自定义网络模型1.bridge驱动2.指定网关和子网3.自定义网络其中内嵌dns解析4.不同网段的容器通信一、源生网络 我们先把server7上的harbor仓库down掉&#xff0c;然后查看网络&#xff0c;可以看…

微服务导学

一、微服务导学1.1 对比单体架构与分布式架构单体架构将业务的所有功能集中再一个项目中开发&#xff0c;打成一个包部署。分布式架构缺点&#xff1a; 模块多导致部署麻烦&#xff1b;架构复杂&#xff0c;难度大1.2 微服务经过良好架构设计的分布式架构方案&#xff0c;微服务…

【Springboot系列】解析Springboot事件机制,从入门到大师

系列文章&#xff1a;Spring Boot学习大纲&#xff0c;可以留言自己想了解的技术点 继续写Springboot系列&#xff0c;争取早点结束。 1、是什么 Spring的事件&#xff08;Application Event&#xff09;为Bean与Bean之间的消息通信提供了支持 事件机制中有三种角色&#x…

RTOS中事件集的实现原理以及实用应用

事件集的原理 RTOS中事件集的实现原理是通过位掩码来实现的。事件集是一种用于在任务之间传递信号的机制。在RTOS中&#xff0c;事件集通常是一个32位的二进制位向量。每个位都代表一个特定的事件&#xff0c;例如信号、标志、定时器等。 当一个任务等待一个或多个事件时&…

Hbase备份与恢复工具Snapshot的基本概念与工作原理

数据库都有相对完善的备份与恢复功能。备份与恢复功能是数据库在数据意外丢失、损坏下的最后一根救命稻草。数据库定期备份、定期演练恢复是当下很多重要业务都在慢慢接受的最佳实践&#xff0c;也是数据库管理者推荐的一种管理规范。HBase数据库最核心的备份与恢复工具——Sna…

Spark+Vue+Springboot 协同过滤额音乐推荐大数据深度学习项目

一、项目背景 随着互联网的发展,大数据的到来,传统的音乐行业受到了很大的冲击,原有的音乐数字化给人们生活带来了极大的便利。随着数字音乐的兴起,各大音乐平台层出不穷,人们在音乐平台上收听音乐的时,常常因为歌曲信息繁杂,而不能找到自己想听的音乐。为了解决这个问题,音乐…

Elasticsearch:使用 Logstash 构建从 Kafka 到 Elasticsearch 的管道 - Nodejs

在我之前的文章 “Elastic&#xff1a;使用 Kafka 部署 Elastic Stack”&#xff0c;我构建了从 Beats > Kafka > Logstash > Elasticsearch 的管道。在今天的文章中&#xff0c;我将描述从 Nodejs > Kafka > Logstash > Elasticsearch 这样的一个数据流。在…

modbus转profinet网关连接ABB变频器在博图程序案例

在博图里PLC无需编程利用兴达易控modbus转Profinet网关,将ABB变频器接入到西门子网络中.用到设备为西门子1200PLC&#xff0c;ABB变频器及兴达易控Modbus转profinet网关一个;兴达易控Modbus转profinet协议转换器&#xff08;XD-MDPN100&#xff09;一台 打开博图添加1200PLC&am…

121.(leaflet篇)leaflet结合echarts4迁徙图

听老人家说:多看美女会长寿 地图之家总目录(订阅之前建议先查看该博客) 文章末尾处提供保证可运行完整代码包,运行如有问题,可“私信”博主。 效果如下所示: 下面献上完整代码,代码重要位置会做相应解释 <!DOCTYPE html> <html>

【数据挖掘与商务智能决策】第二章 特征工程与数据预处理

数据预处理 非数值类型数据处理 Get_dummies哑变量处理 1. 简单示例&#xff1a;“男”和“女”的数值转换 import pandas as pd df pd.DataFrame({客户编号: [1, 2, 3], 性别: [男, 女, 男]}) df客户编号性别01男12女23男 df pd.get_dummies(df, columns[性别]) df客户…

DetectGPT:使用概率曲率的零样本机器生成文本检测

DetectGPT的目的是确定一段文本是否由特定的llm生成&#xff0c;例如GPT-3。为了对段落 x 进行分类&#xff0c;DetectGPT 首先使用通用的预训练模型&#xff08;例如 T5&#xff09;对段落 ~xi 生成较小的扰动。然后DetectGPT将原始样本x的对数概率与每个扰动样本~xi进行比较。…

浏览器主页被hao123劫持的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。喜欢通过博客创作的方式对所学的知识进行总结与归纳,不仅形成深入且独到的理…

Redis哨兵(Sentinel)模式

前言 上一期实现了Redis的主从复制架构&#xff0c;由于主从模式在主节点宕机故障时整个Redis服务都不能再执行写操作&#xff0c;而无法保证Redis在整个系统中的高可用。 Redis提供了Sentinel哨兵机制来解决以上问题&#xff0c;当哨兵服务监测到master下线或宕机&#xff0…

汽车标定知识整理(二):CCP报文基本命令介绍

目录 一、基本命令 CRO命令报文的基本命令表&#xff1a; 二、基本命令与可选命令帧格式介绍 1、CONNECT——建立连接&#xff08;0x01&#xff09; 2、GET_CPP_VERSION——获取CCP版本&#xff08;0x1B&#xff09; 3、SET_MTA——设置内存传输地址&#xff08;0x02&#…

FPGA_边沿监测理解

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