看透SpringSecurity:穿针引线 · SpringSecurity的初始化过程(精)

2023-10-19 04:50

本文主要是介绍看透SpringSecurity:穿针引线 · SpringSecurity的初始化过程(精),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文在公众号,这里的排版有时间再搞,需要的移至文章底部。

 

友情提示:阅读的时候尽量开着电脑一起走。

 

今天聊一下SpringSecurity在SpringBoot下的初始化过程,直接切入正题。

 

先做一些准备工作:
导入maven依赖,

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId><version>1.5.8.RELEASE</version>
</dependency>
根据SpringSecurity官网提示,创建一个配置类,
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
}

好了,我们的准备工作已经完成了……

 

读源码的时候,每遇到一个新的类,都要看一下这个类的继承关系,这个习惯对于读源码很有帮助。(idea快捷键:Ctrl + H)

 

根据WebSecurityConfigurerAdapter的结构,可以大概判定这几个函数需要重写,所以我们的SecurityConfig需要加一些东西,最终是这样的。

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {super.configure(auth);}@Overridepublic void configure(WebSecurity web) throws Exception {super.configure(web);}@Overrideprotected void configure(HttpSecurity http) throws Exception {super.configure(http);}
}

 

想一想,SpringBoot相比Spring一个很明显的特点就是简化了配置流程,先看一下之前在Spring下是如何配置的。

<filter><filter-name>springSecurityFilterChain</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping><filter-name>springSecurityFilterChain</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>

DelegatingFilterProxy相当于一个委托人,将过滤执行 的步骤 委托给springSecurityFilterChain,所以springSecurityFilterChain的创建过程就代表了SpringSecurity的初始化过程。

 

在开始读源码前,必须要清楚所读的内容。SpringSecurity是一个web安全框架,所谓的安全框架,主要的工作就是在处理业务逻辑前做一些安全校验,而安全校验集中在两部分,第一个是http请求本身,比如可能存在csrf(跨站点请求伪造);第二个就是http请求携带的内容(想做的事情) ,需要做一些身份权限校验,今天我们只关注第二个。

身份权限校验,必然少不了业务处理前的拦截以及授权的获取,拦截器组成一个拦截器链,授权的获取需要身份验证器、权限获取中心等,总结一下,一个简单的身份权限校验,需要以下几部分:

filterChain:过滤器链,匹配url

interceptorChain:对匹配到的url做身份权限校验

authenticationManager:身份验证管理

authorizationProvider:role和permission的数据源

 

----------------------------------------------------------

 

下面开始读源码,了解SpringSecurity的初始化过程。

 

以SpringBoot的尿性来看,初始化十有八九是放在了注解里,从@EnableWebSecurity入手。

注解有6个,其中上面3个是做annotation描述的,@Configuration就不解释了,我们要关注的是中间的两个,@Import和@EnableGlobalAuthentication。

 

先看一下@Import导入的第一个类WebSecurityConfiguration,顾名思义,这个是做web安全配置的,SpringSecurityFilterChain的创建过程就藏在这里。

代码不是很多,其中需要注意的是webSecurityConfigurers和webSecurity这两个字段。SpringSecurity是安全框架,安全(Security)就是就是身份(Authentication)+权限(Authorization),身份就是凭据,至于权限包括了role和permission(资源);对于框架来说,需要注意的字眼包括xxConfigure、xxBuilder、xxManager、xxFilter、xxInterceptor这样的字眼。

 

webSecurityConfigurers和WebSecurity都是在这里初始化的,并且我们创建的SecurityConfig也被这两个字段装载,前者添加到了自身(集合),后者添加到了它的webSecurity.configures字段中(集合)。

 

再回到springSecurityFilterChain(),最终的返回结果是由webSecurity.build()构建的,换言之,webSecurity.build()的过程就代表了SpringSecurity的初始化过程,下面来介绍webSecurity.build()的执行步骤。

    1.webSecurity.build()

    2.webSecurity.doBuild() // 真正的构建

构建过程很有意思。buildState标记了构建状态;beforeInit()和beforeConfigure()委托给子类实现;init()做初始化,configure()做配置,configurer()会调用我们创建的SecurityConfigure.configure(WebSecuity),我们覆盖了该函数来配置webSecurity;最后由performBuild()构建返回结果。

有意思的是在init()里面,init()遍历了两个集合做初始化,configures我们知道,刚才webSecurity初始化的时候把我们创建的SecurityConfig放到了这个字段中,而configurersAddedInInitializing则可以在configurers.init()时通过configurers初始化资源的方式初始化,代码中是这个函数:WebSecurity.add(C configure),这样既不影响configurers数据的完整性,又可以在beforeInit()中初始化(Spring的架构真是太美了)。

SecurityConfig.init()实际上是由父类实现的,主要是通过getHttp()初始化了authenticationManager和http两个字段,同时将authenticationManager配置到了authenticatoinBuilder里面,结尾执行了configure(HttpSecurity),没错,就是我们覆盖的3个函数之一,可以在这里配置httpSecurity

authenticationManager()这个函数需要留意,默认是走if取SpringSecurity提供给我们的authenticationManager,但是我们覆盖了configure(AuthenticatonManagerBuilder),所以就会走else,使用我们提供的authenticationManager,而在authenticationManagerBuilder里,又可以自定义数据源(身份信息和role、permission等)。

 

最关键的performBuild(),收尾工作都在这里。有两个新面孔需要关注,ignoredRequests和securityFilterChainBuilders,ignoredRequests可以通过 ignoredRequestRegistry的多个函数初始化资源,securityFilterChainBuilders是在之前SecurityConfig.init()函数里做的资源初始化(其实不算新面孔哈),里边有httpSecurity,图上面有,不贴了。
 

可见最终构建的securityFilterChain由两部分组成,一块儿是不需要拦截的,通过ignoredRequests提供,另一块儿只有一个,就是httpSecurity中filters组成的拦截器链,最终构建出一个FilterChainProxy。

 

回到最开始,还有两个注解没有说完,SpringWebMvcImportSelector通过导入了一个类,来做http请求参数获取,@EnableGlobalAuthentication#AuthenticationConfiguration则提供了一个默认的authenticationManager,如果我们不覆盖configure(AuthenticationManagerBuilder)函数,就会用这个。

 

----------------------------------------------------------

 

结束前我们梳理下整个流程:

 

做个测试:

完美!

 

公众号搜索:以镒称铢

 

这篇关于看透SpringSecurity:穿针引线 · SpringSecurity的初始化过程(精)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/237421

相关文章

Java NoClassDefFoundError运行时错误分析解决

《JavaNoClassDefFoundError运行时错误分析解决》在Java开发中,NoClassDefFoundError是一种常见的运行时错误,它通常表明Java虚拟机在尝试加载一个类时未能... 目录前言一、问题分析二、报错原因三、解决思路检查类路径配置检查依赖库检查类文件调试类加载器问题四、常见

Java注解之超越Javadoc的元数据利器详解

《Java注解之超越Javadoc的元数据利器详解》本文将深入探讨Java注解的定义、类型、内置注解、自定义注解、保留策略、实际应用场景及最佳实践,无论是初学者还是资深开发者,都能通过本文了解如何利用... 目录什么是注解?注解的类型内置注编程解自定义注解注解的保留策略实际用例最佳实践总结在 Java 编程

Java 实用工具类Spring 的 AnnotationUtils详解

《Java实用工具类Spring的AnnotationUtils详解》Spring框架提供了一个强大的注解工具类org.springframework.core.annotation.Annot... 目录前言一、AnnotationUtils 的常用方法二、常见应用场景三、与 JDK 原生注解 API 的

Java controller接口出入参时间序列化转换操作方法(两种)

《Javacontroller接口出入参时间序列化转换操作方法(两种)》:本文主要介绍Javacontroller接口出入参时间序列化转换操作方法,本文给大家列举两种简单方法,感兴趣的朋友一起看... 目录方式一、使用注解方式二、统一配置场景:在controller编写的接口,在前后端交互过程中一般都会涉及

Java中的StringBuilder之如何高效构建字符串

《Java中的StringBuilder之如何高效构建字符串》本文将深入浅出地介绍StringBuilder的使用方法、性能优势以及相关字符串处理技术,结合代码示例帮助读者更好地理解和应用,希望对大家... 目录关键点什么是 StringBuilder?为什么需要 StringBuilder?如何使用 St

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

Maven中引入 springboot 相关依赖的方式(最新推荐)

《Maven中引入springboot相关依赖的方式(最新推荐)》:本文主要介绍Maven中引入springboot相关依赖的方式(最新推荐),本文给大家介绍的非常详细,对大家的学习或工作具有... 目录Maven中引入 springboot 相关依赖的方式1. 不使用版本管理(不推荐)2、使用版本管理(推

Java 中的 @SneakyThrows 注解使用方法(简化异常处理的利与弊)

《Java中的@SneakyThrows注解使用方法(简化异常处理的利与弊)》为了简化异常处理,Lombok提供了一个强大的注解@SneakyThrows,本文将详细介绍@SneakyThro... 目录1. @SneakyThrows 简介 1.1 什么是 Lombok?2. @SneakyThrows

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B