【个人版】SpringBoot下Spring-Security核心概念解读【二】

Spring-Security + HttpSecurity

Spring-Security全局导读:
1、Security核心类设计
2、HttpSecurity结构和执行流程解读
3、Spring-Security个人落地篇

背景: Spring-Security框架的核心架构上一篇已经概述,展示其执行流程及逻辑,但是和我们实际使用有点差距,相信大家在使用此框架时,肯定被以下代码迷惑过:

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().formLogin().disable().authorizeRequests().antMatchers(HttpMethod.OPTIONS).permitAll().anyRequest().authenticated().and().logout().logoutSuccessHandler(authResult).permitAll().and().exceptionHandling().authenticationEntryPoint(authResult);}
}

上述代码直接看就是一串httpSecurity对象的链式配置,但很多问题没有还需明确
1、HttpSecurity可以设置哪些配置点? 重点配置有哪些?
2、链条中为什么需要add方法?是否必须?
3、每个配置点底层以何种形式存在?执行时机或顺序如何定义?
4、HttpSecurity除了链式配置外,还需要哪些配置?
5、在适配模式下使用,重写的configure方法何时执行?
6、HttpSecurity在何处以何种方式被使用的?

下面将在以上问题的基础上,对HttpSecurity做自我理解后的解读:
基础条件:
1、SpringBoot的Web项目【版本2.7.14】
2、集成相关spring-security的starter依赖

解答一、HttpSecurity的由来
上下文自动配置类:
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration

引入Security注解开关:
org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
传递关系(依次由上到下):

  • SecurityAutoConfiguration
  • SpringBootWebSecurityConfiguration
  • WebSecurityEnablerConfiguration
  • EnableWebSecurity

进而引入Security框架核心类的配置类:
AuthenticationConfiguration => AuthenticationManager管理类
WebSecurityConfiguration => WebSecurity配置类
HttpSecurityConfiguration => HttpSecurity配置类

HttpSecurity创建代码简化版:

@Configuration(proxyBeanMethods = false
)
class HttpSecurityConfiguration {private ObjectPostProcessor<Object> objectPostProcessor; // 框架类初始化增强类,后续单独讲private AuthenticationManager authenticationManager; // 授权管理器,核心依赖类,可自定义,可系统自动配置,后续单独讲private AuthenticationConfiguration authenticationConfiguration; // 授权管理器配置类,作为父授权管理器托底private ApplicationContext context;@Scope("prototype")@Bean({"org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.httpSecurity"})HttpSecurity httpSecurity() throws Exception {WebSecurityConfigurerAdapter.LazyPasswordEncoder passwordEncoder = new WebSecurityConfigurerAdapter.LazyPasswordEncoder(this.context);// 创建授权管理器构建类,parent设置时可以全局搜索我们自定义的AuthenticationProvider类,就不用通过构建器手工设置AuthenticationManagerBuilder authenticationBuilder = new WebSecurityConfigurerAdapter.DefaultPasswordEncoderAuthenticationManagerBuilder(this.objectPostProcessor, passwordEncoder);authenticationBuilder.parentAuthenticationManager(this.authenticationManager());// 实例化HttpSecurityHttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, this.createSharedObjects());// 初始化HttpSecurity安全管理逻辑,如logout、登录页、异常等场景设置,都是默认配置,做到开箱即用http.csrf(Customizer.withDefaults()).addFilter(new WebAsyncManagerIntegrationFilter()).exceptionHandling(Customizer.withDefaults()).headers(Customizer.withDefaults()).sessionManagement(Customizer.withDefaults()).securityContext(Customizer.withDefaults()).requestCache(Customizer.withDefaults()).anonymous(Customizer.withDefaults()).servletApi(Customizer.withDefaults()).apply(new DefaultLoginPageConfigurer());http.logout(Customizer.withDefaults());        this.applyDefaultConfigurers(http); // SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader) -- 默认factories加载实现类,忽略	return http;}private AuthenticationManager authenticationManager() throws Exception {return this.authenticationManager != null ? this.authenticationManager : this.authenticationConfiguration.getAuthenticationManager();}// HttpSecurity内部全局共享实例集合,核心类都会在此保存并重复使用private Map<Class<?>, Object> createSharedObjects() {Map<Class<?>, Object> sharedObjects = new HashMap();sharedObjects.put(ApplicationContext.class, this.context);return sharedObjects;}
}

除代码中标注的注释外,还需要注意:
1、注意HttpSecurity上@Bean发布范围是多例,因为可以Proxy下可以配置多个过滤器链(注:如果在不同类或同一个类的不同地方多次引用,相关配置会错乱,除非自己另行全局封装)
2、AuthenticationManager是部分Filter的核心依赖,尤其涉及我们自定义鉴权部分的代码,其主旨为拦截后对接口具体的参数处理与返回,也就是我们的鉴权逻辑。

解答二:HttpSecurity结构之配置与构建过程
作为一个框架的核心类,HttpSecurity的设计完成应用了多个巧妙的设计模式,使代码可读性、复用性更高。
核心设计模式一:构建器模式
构建器模式是最常见的创建型模式,在类相关实例变量相当多的场景下非常实用,避免长列表或多重载构造函数。在Security框架中,安全策略多样,每个安全策略需要管理的参数量不固定且灵活性较高(隐含意思是:HttpSecurity配置安全策略及安全策略配置具体参数都适用此场景,实际security框架就是这么设计和干的),如果采用常见if…else…语法,配置及使用过程将毫无人性,构建器模式让HttpSecurity的链式配置更加易读和使用。

Spring6中将配置器的创建改成lambda形式,进一步缩短HttpSecurity的配置层次,将配置器的创建与HttpSecurity的配置解耦,这就是框架的魅力。

构建器模式代码结构很简单,难点在于安全知识点的理解与调控,开发过程中注意参数变化导致的配置器的失效问题,下面将简单列举来进一步说明:
在这里插入图片描述
1、图中1处的logout无参方法返回配置器Configurer的实例对象,我们通过配置内部构建方法进一步配置其他参数值,结束配置可用HttpSecurity另起一行配置新的配置器,或者使用logout配置器的and方法继续链式配置其他配置器
2、图中2处的logout有参方法提供了一个自定义构造器参数,可以对系统默认的Configurer实例做进一步配置,可对象可由lambda表达式代替,Spring6已经全面像此场景靠拢(部分人对过长的HttpSecurity链无感)

配置器操作中其实隐含一个非常重要的操作,可以看到图中的getOrApply方法。该方法一方面将Configurer实例添加到HttpSecurity的全局缓存中,并将HttpSecurity的实例对象的引用传递进原Configurer内部,做到相交相融,还有将Configurer从普通new出的实例进一步提级,完成类似spring容器里的实例对象的生命周期的管理。根据反馈效果,后续可追加解读。

核心设计模式二:模板模式
模板模式常用在继承结构,HttpSecurity继承了AbstractConfiguredSecurityBuilder -> AbstractSecurityBuilder抽象类,该抽象类将构建方法完全委托给实现类完成,已知实现类有:HttpSecurity、WebSecurity、AuthenticationManagerBuilder,可以看到这三个类正是Security框架的核心。模板模式特点之xxx -> doXxx,构建过程如下:

protected final O doBuild() throws Exception {synchronized(this.configurers) {this.buildState = AbstractConfiguredSecurityBuilder.BuildState.INITIALIZING;this.beforeInit();this.init();this.buildState = AbstractConfiguredSecurityBuilder.BuildState.CONFIGURING;this.beforeConfigure();this.configure();this.buildState = AbstractConfiguredSecurityBuilder.BuildState.BUILDING;O result = this.performBuild();this.buildState = AbstractConfiguredSecurityBuilder.BuildState.BUILT;return result;}
}

构建流程说明:
1、beforeInit()

  • 尴尬,三个实现类都忽略了

2、init()

  • 执行所有安全配置器的初始化代码,即configurer.init(HttpSecurity)

3、beforeConfigure()

  • 授权管理器实例化并添加到sharedObjects集合,AuthenticationManagerBuilder在此构建后状态标记已变更,不可重新变更,只能获取并使用。构建后的实例,可以注入到HttpSecurity中可以创建Filter的配置器中,自定义安全Filter需要人工或特殊配置来设置。(这块有一定的操作空间)

4、configure()

  • 这个方法和init方法相辅相成,前面已经完成各配置器的初始化,现完成调用各配置器Configurer的configure方法,逐一完成对HttpSecurity的配置。(此块即完成security框架内部Filter的添加,例:LogoutFilter)

5、performBuild()

  • HttpSecurity构建的结果就是SecurityFilterChain对象,此对象的功能就是用来管理security内部Filter集合,创建逻辑也很简单:new DefaultSecurityFilterChain(this.requestMatcher, sortedFilters)。关于SecurityFilterChain的介绍,请点击并移步至此篇。

概要说明:
1、构建流程的入口是我们HttpSecurity.build方法,该方法可由我们主动触发,在WebSecurityConfigurerAdapter适配器模式下,由框架触发
2、授权管理器用来鉴权逻辑,所以一般配置器生产的Filter实例可不用配置,必要的Filter也会做检查。授权管理器对应的构建器在代码里有一定的操作空间,其构建状态影响较大。
3、添加到HttpSecurity的内部安全Filter有很多,这些Filter不影响我们正常使用的ApplicationFilterChain的执行流程,各Filter在集合中的顺序有默认顺序(详见FilterOrderRegistration,包含所有内部过滤器清单及Order),自定义Filter可通过HttpSecurity.addFilterBefore/After等方法指定。

总结:
通过上述两大设计模式对Security框架的解读,文章开篇的几个问题基本都涵盖了,自己可以对照着解读,根据问题和自己的理解去源码中进一步验证,再来一遍debug,基本就可以结束了。下面文章将根据这两篇前缀,直接出一个完整的个人版落地篇,也就是我们实际使用这个框架的内容了。

PS:还有一个重要流程其实没有阐述,就是上一篇的FilterChainProxy与本篇的HttpSecurity构建的SecurityFilterChain对象是如何绑定的,其答案为:WebSecurity通过控制HttpSecurity的配置与构建过程生成SecurityFilterChain,在对应构建方法中使用FilterChainProxy包装,进而发布到外部ApplicationFilterChain过滤器链中。如果感兴趣,以后有机会再开篇详解。

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

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

相关文章

【期末考复习向】transformer的运作机制

1.transformer的encoder运作 transformer的encoder部分包括了输入和处理2大部分。首先是输入部分inputs&#xff0c;这里初始的inputs是采用独热向量进行表示的&#xff0c;随后经过word2vec等操作把独热向量&#xff08;采用独热向量的好处就是可向量是正交的&#xff0c;可以…

re:Invent 产品体验分享:Amazon ElastiCache Serverless 缓存即时扩展功能与感受

授权说明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在亚马逊云科技开发者社区、 知乎、自媒体平台、第三方开发者媒体等亚马逊云科技官方渠道&#xff09;。 文章目录 前言产品介绍产品使用步骤1.创建缓存服务2.安全组开放访问权限…

C++从bing采集各行业的企业官网信息

作为一名合格的销售&#xff0c;除了自己的人脉&#xff0c;还应该有新鲜的客户加入并发掘。不管哪行哪业&#xff0c;知彼知己&#xff0c;方才能做到百战百胜。今天我就用我们的专业技能&#xff0c;让销售获取更多同行业的公开企业信息&#xff0c;让业绩顺风顺水。 通常在C…

如何实现电脑文件夹自动备份?以下是图解教程

在当今迅猛发展的科技时代&#xff0c;电脑已经成为不可或缺的办公工具。随着使用时间的增加&#xff0c;存储在电脑中的文件数量也逐渐增多。然而&#xff0c;由于设备故障、手动误删等原因&#xff0c;文件的丢失问题成为一个不可忽视的风险。如果丢失的文件具有重要性&#…

数学learning

目录 移动平均 简单移动平均 加权移动平均 指数移动平均 矩阵求导 矩阵对标量求导 Matrix-by-scalar 标量对矩阵求导 Scalar-by-matrix 参考博客 移动平均 优化算法里面会涉及到一个知识点&#xff1a;指数移动平均。 但是为了知识的完整性&#xff0c;这里会将常见的移动…

MCU平台下一种简单的文件系统设计构想

本文介绍MCU平台下一种简单的文件系统设计构想。 在使用MCU的项目中&#xff0c;经常会涉及到一些数据的存储&#xff0c;受限于硬件&#xff0c;又不太可能直接上文件系统&#xff08;如FAT文件系统&#xff09;&#xff0c;直接指定存储地址&#xff0c;数据长度对数据进行读…

React antd如何实现<Upload>组件上传附件再次上传已清除附件缓存问题

最近遇到一个React上传组件的问题&#xff0c;即上传附件成功后&#xff0c;文件展示处仍然还有之前上传附件的缓存信息&#xff0c;需要解决的问题是&#xff0c;要把上一次上传的附件缓存在上传成功或者取消后&#xff0c;可以进行清除 经过一顿试错&#xff0c;终于解决了这…

SE考研真题总结(二)

接上条&#xff0c;今天继续更新~ SE考研真题总结&#xff08;一&#xff09;-CSDN博客文章浏览阅读340次&#xff0c;点赞6次&#xff0c;收藏11次。本帖开始分享考研真题中设计【软件工程】的部分&#xff0c;预计会出5期左右&#xff0c;敬请期待~https://blog.csdn.net/js…

EasyRecovery(数据恢复软件) 2024中文绿色无需激活版下载

EasyRecovery是一款功能强大且专业的数据恢复软件&#xff0c;软件能够对电脑误删的文件进行恢复&#xff0c;包括格式化硬盘是数据恢复、手机U盘数据恢复等&#xff0c;小编今天给大家带来的是根据官软件解压后直接使用。感兴趣的朋友快来下载使用吧。 EasyRecovery-2024mac最…

Pytorch-CNN轴承故障一维信号分类(二)

目录 前言 1 数据集制作与加载 1.1 导入数据 1.2 数据加载&#xff0c;训练数据、测试数据分组&#xff0c;数据分batch 2 CNN-2D分类模型和训练、评估 2.1 定义CNN-2d分类模型 2.2 定义模型参数 2.3 模型结构 2.4 模型训练 2.5 模型评估 3 CNN-1D分类模型和训练、评…

flink找不到隐式项

增加 import org.apache.flink.streaming.api.scala._ 即可

改进的A*算法的路径规划(2)

子节点优化选择策略 (1)子节点选择方式 为了找到从起始点到终点的路径&#xff0c;需定义一种可以选择后续节点的方式。在 A*算法中两种常见的方法为4-邻接(见图5-7(a) 和8-邻接(见图5-7(b)), 但考虑到 在复杂越野环境上&#xff0c;我们希望智能车辆允许更多的自由运动来更…

MSF学习

之前的渗透测试中 其实很少用到 cs msf 但是在实际内网的时候 可以发现 msf cs 都是很好用的 所以现在我来学习一下 msf的使用方法 kali自带msf https://www.cnblogs.com/bmjoker/p/10051014.html 使用 msfconsole 启动即可 首先就是最正常的木马生成 所以这里其实只需…

分类预测 | Matlab实现DBO-SVM蜣螂算法优化支持向量机的数据分类预测【23年新算法】

分类预测 | Matlab实现DBO-SVM蜣螂算法优化支持向量机的数据分类预测【23年新算法】 目录 分类预测 | Matlab实现DBO-SVM蜣螂算法优化支持向量机的数据分类预测【23年新算法】分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现DBO-SVM蜣螂算法优化支持向量机的…

数理统计基础:参数估计与假设检验

在学习机器学习的过程中&#xff0c;我充分感受到概率与统计知识的重要性&#xff0c;熟悉相关概念思想对理解各种人工智能算法非常有意义&#xff0c;从而做到知其所以然。因此打算写这篇笔记&#xff0c;先好好梳理一下参数估计与假设检验的相关内容。 1 总体梳理 先从整体结…

串口通信(4)-C#串口通信入门实例

本文通过实例讲解C#串口通信。 入门实例设计一个串口助手&#xff0c;能够很好的涵盖串口要点的使用。 目录 一、成品图 二、界面文件 三、后台代码 四、实例中要点 一、成品图 如下&#xff1a; 实现的过程 创建winform项目&#xff0c;将Form1文件的名称改为MainForm&…

Windows汇编调用printf

VS2022 汇编 项目右键 生成依赖项 生成自定义 勾选masm 链接器 高级 入口点 main X86 .686 .model flat,stdcall option casemap:none includelib ucrt.lib includelib legacy_stdio_definitions.libEXTERN printf:proc.data szFormat db %s,0 szStr db hello,0.code main…

关于职场伪勤奋

前段时间看了一些关于勤奋学习、职场成长类的书籍&#xff0c;就在思考勤奋学习和职场的关系时&#xff0c;结合个人的理解&#xff0c;我定义了一种勤奋叫职场“伪勤奋”。那关于职场“伪勤奋”的定义和理解&#xff0c;与大家分享&#xff1a; 1、选择性任务完成 伪勤奋特征…

vue 图片等比例缩放上传

需求&#xff1a;上传图片之前按比例缩小图片分辨率&#xff0c;宽高不超过1920不处理图片&#xff0c;宽高超过1920则缩小图片分辨率&#xff0c;如果是一张图片请参考这篇博客&#xff1a;js实现图片压缩、分辨率等比例缩放 我根据这篇博主的分享&#xff0c;写下了我的循环上…

HarmonyOS使用Web组件

Web组件的使用 1 概述 相信大家都遇到过这样的场景&#xff0c;有时候我们点击应用的页面&#xff0c;会跳转到一个类似浏览器加载的页面&#xff0c;加载完成后&#xff0c;才显示这个页面的具体内容&#xff0c;这个加载和显示网页的过程通常都是浏览器的任务。 ArkUI为我…