diff --git "a/Spring-Security/src/main/doc/SpringSecurity/SpringSecurity\345\222\214OAuth2\357\274\210\344\270\200\357\274\211\342\200\224\342\200\224 \345\210\235\350\257\206SpringSecurity.md" "b/Spring-Security/src/main/doc/SpringSecurity/SpringSecurity\345\222\214OAuth2\357\274\210\344\270\200\357\274\211\342\200\224\342\200\224 \345\210\235\350\257\206SpringSecurity.md"
new file mode 100644
index 0000000..9f61fff
--- /dev/null
+++ "b/Spring-Security/src/main/doc/SpringSecurity/SpringSecurity\345\222\214OAuth2\357\274\210\344\270\200\357\274\211\342\200\224\342\200\224 \345\210\235\350\257\206SpringSecurity.md"
@@ -0,0 +1,185 @@
+
+- [前言](#前言)
+- [正文](#正文)
+ - [1. 初识SpringSecurity](#1-初识springsecurity)
+ - [2. Spring Security项目核心jar包介绍](#2-spring-security项目核心jar包介绍)
+ - [3. SpringSecurity核心注解](#3-springsecurity核心注解)
+ - [3.1 @EnableWebSecurity](#31-enablewebsecurity)
+ - [3.2 @EnableGlobalAuthentication](#32-enableglobalauthentication)
+ - [3.3 @EnableGlobalMethodSecurity](#33-enableglobalmethodsecurity)
+ - [4. SpringSecurity核心组件](#4-springsecurity核心组件)
+ - [4.1 认证](#41-认证)
+ - [4.2 授权](#42-授权)
+ - [5. SpringSecurity中的Filter](#5-springsecurity中的filter)
+ - [5.1 FilterChainProxy以及其内部的Filter](#51-filterchainproxy以及其内部的filter)
+- [总结](#总结)
+- [参考](#参考)
+- [相关文章](#相关文章)
+
+## 前言
+相信了解过SpringSecurity或者是OAuth2的读者,会发现网上会有非常多的相关文章,或是纯概念的,或是带有demo的,无论是哪种类型的文章,本人去阅读之后,对于整个框架的概念还是一知半解,也仅仅是实现了某些功能、某些效果而已,若遇到某些问题时无从下手,只能去百度去Google。这是因为对于SpringSecurity和OAuth2的知识没有一个整体概念的把握,知识体系没有形成系统,遂决定写一个关于SpringSecurity和OAuth2的系列专栏,在构建自己知识体系的同时还希望能帮助有同样困惑的同学。
+
+**本专栏希望通过通俗易懂的语言来达到从入门概念、demo开始,由简入深,最终能达到深谙其底层源码的目的。**
+
+## 正文
+### 1. 初识SpringSecurity
+对于SpringSecurity,可以由其官网中的介绍了解到其概述:
+1. SpringSecurity就是一个功能强大且高定制化的身份验证和访问控制框架,它事实上就是一个保护基于Spring的应用框架安全性的标准。
+2. Spring Security是一个重点为Java应用程序提供身份验证和授权的框架。
+3. 与所有Spring项目一样,Spring Security的真正强大之处在于它可以很容易地扩展以满足定制需求
+
+对于SpringSecurity的特性,可以总结为以下几点:
+1. 对身份认证和授权提供全面和可扩展的支持。
+2. 防止会话固定、劫持请求、跨站点请求伪造等攻击。
+3. Servlet API的集成。
+4. 与Spring Web MVC的可选集成。
+
+在进行代码编写时,先得对SpringSecurity有一个整体上的认识,等进行coding时才能知道对应代码的对应作用。
+
+### 2. Spring Security项目核心jar包介绍
+在SpringSecurity继承的项目中,主要有四个核心的jar包:
+
+- spring-security-core.jar
+ SpringSecurity的核心包,任何SpringSecurity的功能都需要此包。
+- spring-security-web.jar
+ web工程必备,包含过滤器和相关的Web安全基础结构代码。
+- spring-security-config.jar
+ 用于解析xml配置文件,用到SpringSecurity的xml配置文件的就要用到此包。
+
+由于spring-security-web.jar和spring-security-config.jar 都依赖了spring-security-core.jar,所以只需要导入spring-security-web.jar和spring-security-config.jar 即可。
+
+> 本专栏系列文章相关demo版本:
+> SpringBoot: 2.1.14.RELEASE
+
+```
+
+
+ org.springframework.security
+ spring-security-config
+ 5.1.10.RELEASE
+
+
+
+ org.springframework.security
+ spring-security-web
+ 5.1.10.RELEASE
+
+```
+
+
+
+不过,在SpringBoot中的spring-boot-starter-security中,就已经依赖好了spring-security-web.jar和spring-security-config.jar,直接拿来用即可。
+
+
+
+既然SpringBoot都已经定义好了spring-boot-starter-security,那就用spring-boot-starter-security吧,这样做的好处是能够方便SpringBoot统一SpringSecurity的版本。
+
+### 3. SpringSecurity核心注解
+SpringBoot集成SpringSecurity需要配置几个配置文件,并且需要几个核心注解,下面来依次介绍这些注解。
+
+#### 3.1 @EnableWebSecurity
+@EnableWebSecurity是Spring Security用于启用Web安全的注解。典型的用法是该注解用在某个Web安全配置类上(实现了接口WebSecurityConfigurer或者继承自WebSecurityConfigurerAdapter)。
+```
+@Configuration
+@EnableWebSecurity
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+...
+}
+```
+
+
+从注解源码可以看到,该注解有如下作用:
+1. 控制Spring Security是否使用调试模式(通过注解属性debug指定),默认为false,表示缺省不使用调试模式。
+2. 导入 WebSecurityConfiguration,用于配置Web安全过滤器FilterChainProxy,并创建过滤器链springSecurityFilterChain来保护你的Spring应用。
+3. 如果是Servlet 环境,导入WebMvcSecurityConfiguration。
+4. 如果是OAuth2环境(spring-security-oauth2-client),导入OAuth2ClientConfiguration。
+5. 使用注解@EnableGlobalAuthentication启用全局认证机制,即全局的AuthenticationManager,AuthenticationManager会在运行时对请求着进行身份验证。
+
+#### 3.2 @EnableGlobalAuthentication
+@EnableGlobalAuthentication是包含在了@EnableWebSecurity注解中的,作用通过启用认证管理器(AuthenticationManager)来启用全局认证机制。
+
+核心逻辑就在AuthenticationConfiguration类里。
+
+在AuthenticationConfiguration在SpringSecurity中扮演者非常重要的作用,它内部包含了AuthenticationManager用于核心的认证工作。接下来将会重点讲解该类。
+
+
+#### 3.3 @EnableGlobalMethodSecurity
+Spring Security默认是禁用注解的,要想开启注解,需要在继承WebSecurityConfigurerAdapter的类上加@EnableGlobalMethodSecurity注解,来判断用户对某个控制层的方法是否具有访问权限。
+
+除此之外,还可以在@EnableGlobalMethodSecurity中添加几个属性。
+
+1. @EnableGlobalMethodSecurity(securedEnabled=true)开启@Secured 注解过滤权限。
+2. @EnableGlobalMethodSecurity(jsr250Enabled=true)开启@RolesAllowed 注解过滤权限 。
+3. @EnableGlobalMethodSecurity(prePostEnabled=true)使用表达式时间方法级别的安全性 4个注解可用。
+ - @PreAuthorize 在方法调用之前,基于表达式的计算结果来限制对方法的访问
+ - @PostAuthorize 允许方法调用,但是如果表达式计算结果为false,将抛出一个安全性异常
+ - @PostFilter 允许方法调用,但必须按照表达式来过滤方法的结果
+ - @PreFilter 允许方法调用,但必须在进入方法之前过滤输入值
+
+
+### 4. SpringSecurity核心组件
+在SpringSecurity中,有着许多的组件包括AuthenticationManager、AccessDesicionManager和UsernamePasswordAuthenticationFilter等。
+
+对于SpringSecurity来说,最大的两个问题就是:**认证(Authentication,即你是谁?)和授权(Authorization,允许你做什么?)**。SpringSecurity框架旨在将认证从授权中剥离出来,并也有适用于二者的策略和可扩展的设计。
+
+#### 4.1 认证
+在SpringSecurity中,用于认证的主要接口是AuthenticationManager,它只有一个方法:
+```
+public interface AuthenticationManager {
+ Authentication authenticate(Authentication authentication)
+ throws AuthenticationException;
+}
+```
+
+AuthenticationManger最普遍的实现类是ProviderManager,而ProviderManager会将认证委托给AuthenticationProvider。
+
+
+AuthenticationProvider接口和AuthenticationManager相似,但是它有一个额外的方法允许查询它支持的Authentication方式:
+```
+public interface AuthenticationProvider {
+ Authentication authenticate(Authentication authentication)
+ throws AuthenticationException;
+
+ boolean supports(Class> authentication);
+}
+```
+
+
+#### 4.2 授权
+
+一旦认证成功,我们就可以进行授权了,它核心的策略就是AccessDecisionManager。同样的,它将授权逻辑全部委托给AccessDecisionVoter来实现。
+
+一个AccessDecisionVoter考虑一个Authentication(代表一个Principal)和一个被ConfigAttributes装饰的安全对象,这里的ConfigAttributes就是一个包含了URL以及这个URL该有权限的对象的集合。
+```
+boolean supports(ConfigAttribute attribute);
+
+boolean supports(Class> clazz);
+
+int vote(Authentication authentication, S object,
+ Collection attributes);
+```
+
+现在,已经拥有了认证和授权组件了,那么一个HTTP请求进入SpringSecurity应用时,经过过滤器链中都发生了哪些逻辑?接下来就看下SpringSecurity中过滤器链底层都发生了什么。
+
+### 5. SpringSecurity中的Filter
+除了认证和授权外,SpringSecurity的另外一个核心就是Servlet的Filter来实现的。先简单回顾下Servlet中Filter的调用原理。
+下图展示了处理单个HTTP请求的经典分层结构图:
+ 
+客户端向服务器发起请求,然后Servlet容器(Tomcat)会根据URI来决定哪个Filter和哪个Servlet适用于这个请求,一个Servlet最多处理一个请求,过滤器是链式的,它们是有顺序的。事实上一个过滤器可以否决接下来的过滤器,上一个过滤器请求处理完就会动过调用Filter的doFilter()向下传递请求,知道请求最终到达Servlet处理完毕后,再过滤器以相反的顺序调用,再以Response返回给客户端。
+
+#### 5.1 FilterChainProxy以及其内部的Filter
+
+回归正题,SpringSecurity在过滤器链中扮演的就是一个Filter,其类型是FilterChainProxy。但它又不是一个普通的Filter,因为FilterChainProxy中包含了额外的过滤器,每个过滤器都发挥特殊的作用。下面用一张图展示下FliterChainProxy中包含的过滤器链。
+
+在SpringBoot中,SpringSecurity的FilterChainProxy是以bean的形式注入到Spring容器中的,并且它是默认配置,所以在每次请求中都会存在,所以在SpringSecurity保护的应用中,每次请求都会经过FilterChainProxy。
+
+## 总结
+本片文章粗略的讲解了SpringSecurity里的几个核心概念,包括:核心注解、认证和授权的核心组件以及SpringSecurity中的FilterChainProxy,整个SpringSecurity框架就是围绕着这几个核心概念运行,下面几章将会深入分析每个核心概念的底层运行机制。
+
+## 参考
+- [《spring-security-architecture》](https://spring.io/guides/topicals/spring-security-architecture)
+- [《Spring Security Reference》](https://docs.spring.io/spring-security/site/docs/current/reference/html5/#preface)
+
+## 相关文章
+- [从零开始系统学习SpringSecurity和OAuth2(二)—— 安全过滤器FilterChainProxy](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/SpringSecurity/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0SpringSecurity%E5%92%8COAuth2%EF%BC%88%E4%BA%8C%EF%BC%89%E2%80%94%E2%80%94%20%E5%AE%89%E5%85%A8%E8%BF%87%E6%BB%A4%E5%99%A8FilterChainProxy.md)
+- [从零开始系统学习SpringSecurity和OAuth2(三)—— WebSecurity建造核心逻辑](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/SpringSecurity/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0SpringSecurity%E5%92%8COAuth2%EF%BC%88%E4%B8%89%EF%BC%89%E2%80%94%E2%80%94%20WebSecurity%E5%BB%BA%E9%80%A0%E6%A0%B8%E5%BF%83%E9%80%BB%E8%BE%91.md)
\ No newline at end of file
diff --git "a/Spring-Security/src/main/doc/SpringSecurity/SpringSecurity\345\222\214OAuth2\357\274\210\344\270\211\357\274\211\342\200\224\342\200\224 WebSecurity\345\273\272\351\200\240\346\240\270\345\277\203\351\200\273\350\276\221.md" "b/Spring-Security/src/main/doc/SpringSecurity/SpringSecurity\345\222\214OAuth2\357\274\210\344\270\211\357\274\211\342\200\224\342\200\224 WebSecurity\345\273\272\351\200\240\346\240\270\345\277\203\351\200\273\350\276\221.md"
new file mode 100644
index 0000000..3d6cfb6
--- /dev/null
+++ "b/Spring-Security/src/main/doc/SpringSecurity/SpringSecurity\345\222\214OAuth2\357\274\210\344\270\211\357\274\211\342\200\224\342\200\224 WebSecurity\345\273\272\351\200\240\346\240\270\345\277\203\351\200\273\350\276\221.md"
@@ -0,0 +1,308 @@
+
+ - [前言](#前言)
+ - [正文](#正文)
+ - [1. AbstractConfiguredSecurityBuilder中安全配置类](#1-abstractconfiguredsecuritybuilder中安全配置类)
+ - [2. AbstractConfiguredSecurityBuilder的doBuild()方法](#2-abstractconfiguredsecuritybuilder的dobuild方法)
+ - [3. WebSecurity中的performBuild()方法](#3-websecurity中的performbuild方法)
+- [总结](#总结)
+- [相关文章](#相关文章)
+
+## 前言
+相信了解过SpringSecurity或者是OAuth2的读者,会发现网上会有非常多的相关文章,或是纯概念的,或是带有demo的,无论是哪种类型的文章,本人去阅读之后,对于整个框架的概念还是一知半解,也仅仅是实现了某些功能、某些效果而已,若遇到某些问题时无从下手,只能去百度去Google。这是因为对于SpringSecurity和OAuth2的知识没有一个整体概念的把握,知识体系没有形成系统,遂决定写一个关于SpringSecurity和OAuth2的系列专栏,在建造自己知识体系的同时还希望能帮助有同样困惑的同学。
+
+============== 分割线 ==============
+
+上一章已经讲解到了SpringSecurity用到了建造者模式来建造FilterChainProxy。本片就来详细分析下WebSecurity的核心逻辑以及AbstractConfiguredSecurityBuilder的doBuild()方法。
+
+## 正文
+
+### 1. AbstractConfiguredSecurityBuilder中安全配置类
+SpringSecurity通过SecurityConfigurer来建造FilterChainProxy,建造前还需要进行配置。因此AbstractConfiguredSecurityBuilder还需要注入配置组件SecurityConfigurer,初始化配置组件SecurityConfigurer,调用SecurityConfigurer的configure方法。
+
+在AbstractConfiguredSecurityBuilder类中,看下安全配置类的定义:‘
+
+```
+private final LinkedHashMap>, List>> configurers = new LinkedHashMap>, List>>();
+```
+这是定义的安全配置器的子类Map集合,这个configurers就是用于初始化以及配置FilterChainProxy中的filters用的。Map集合中,Key是SecurityConfigurer的子类的Class类型,Value是SecurityConfigurer的list集合。
+
+作为一个成员变量,自然会有方法从外部注入安全配置类。在AbstractConfiguredSecurityBuilder的类中,定义了add方法。
+
+```
+ private > void add(C configurer) throws Exception {
+ Assert.notNull(configurer, "configurer cannot be null");
+ // 获取安全配置类的Class类型
+ Class extends SecurityConfigurer> clazz = (Class extends SecurityConfigurer>) configurer
+ .getClass();
+ // 同步去操作安全配置类集合
+ synchronized (configurers) {
+ // 查看建造状态是否是已经配置
+ if (buildState.isConfigured()) {
+ throw new IllegalStateException("Cannot apply " + configurer
+ + " to already built object");
+ }
+ // 如果allowConfigurersOfSameType为true,则从configurers集合中获取clazz类型的安全配置类集合
+ List> configs = allowConfigurersOfSameType ? this.configurers
+ .get(clazz) : null;
+ if (configs == null) {
+ // 初始化安全配置类结合
+ configs = new ArrayList>(1);
+ }
+ // 将安全配置类添加至configs的list集合中
+ configs.add(configurer);
+ // 以clazz为key,configs为value存入configurers的LinkedHashMap集合中
+ this.configurers.put(clazz, configs);
+ if (buildState.isInitializing()) {
+ this.configurersAddedInInitializing.add(configurer);
+ }
+ }
+ }
+
+```
+
+通过IDEA来查看下哪些地方调用了add方法
+
+
+看下apply方法
+```
+ // 传入的C是SecurityConfigurerAdapter的子类,
+ public > C apply(C configurer)
+ throws Exception {
+ // 传入objectPostProcessor,该对象用于创建各种“实例”,具体什么作用下问会讲解,请留意
+ configurer.addObjectPostProcessor(objectPostProcessor);
+ // 将当前对象设置为建造者
+ configurer.setBuilder((B) this);
+ // 调用add方法,向configurers集合中添加configurer
+ add(configurer);
+ return configurer;
+ }
+
+```
+
+继续查看apply方法有哪些地方调用了的
+
+图上的HttpSecurity的getOrApply方法值得注意一下,查看其方法
+```
+ private > C getOrApply(
+ C configurer) throws Exception {
+ // 从configurers集合中获取安全配置类
+ C existingConfig = (C) getConfigurer(configurer.getClass());
+ if (existingConfig != null) {
+ // 如果存在则直接返回该安全配置类
+ return existingConfig;
+ }
+ // 如果不存在则调用apply方法去应用该安全配置类,并缓存到configurers集合中
+ return apply(configurer);
+ }
+
+```
+
+getOrApply方法主要是从configurers集合中获取配置类,如果存在则直接返回,否则则应用该配置类。
+
+继续查看getOrApply有哪些地方在调用。这下终于看到了安全配置类了。
+
+
+这里有一个问题值得思考,这些配置类到底是干嘛用的?这里就以ExpressionUrlAuthorizationConfigurer配置类为例,看下其类内部configure方法逻辑。
+
+找了一圈,发现configure的实现是在ExpressionUrlAuthorizationConfigurer的抽象父类AbstractInterceptUrlConfigurer定义的。
+
+```
+ @Override
+ public void configure(H http) throws Exception {
+ // 创建元数据,该抽象方法由ExpressionUrlAuthorizationConfigurer定义,返回一个ExpressionBasedFilterInvocationSecurityMetadataSource对象
+ FilterInvocationSecurityMetadataSource metadataSource = createMetadataSource(http);
+ // 如果配置失败,则数据源配置失败
+ if (metadataSource == null) {
+ return;
+ }
+ // 创建一个FilterSecurityInterceptor对象
+ FilterSecurityInterceptor securityInterceptor = createFilterSecurityInterceptor(
+ http, metadataSource, http.getSharedObject(AuthenticationManager.class));
+ if (filterSecurityInterceptorOncePerRequest != null) {
+ securityInterceptor
+ .setObserveOncePerRequest(filterSecurityInterceptorOncePerRequest);
+ }
+ // 通过objectPostProcessor创建一个securityInterceptor实例对象
+ securityInterceptor = postProcess(securityInterceptor);
+ http.addFilter(securityInterceptor);
+ // 将实例对象存入SharedObject缓存中
+ http.setSharedObject(FilterSecurityInterceptor.class, securityInterceptor);
+ }
+
+```
+
+从ExpressionUrlAuthorizationConfigurer的抽象父类AbstractInterceptUrlConfigurer可以看出,configure方法中调用了一个postProcess方法,该方法用于生成FilterSecurityInterceptor对象,在本系列文章前面第一章以及列出来的FilterChainProxy拦截器链对象,可以知道FilterSecurityInterceptor对象就属于FilterChainProxy拦截器链中的对象,并且是处在最后一个位置。
+
+到此处,安全配置类的作用已经提现出来了,就是向sharedObject中添加过滤器,并最终注入到FilterChainProxy中。
+
+### 2. AbstractConfiguredSecurityBuilder的doBuild()方法
+随着configurers集合元素的注入,下面就是进行建造工作,调用doBuild()方法。
+
+```
+ @Override
+ protected final O doBuild() throws Exception {
+ synchronized (configurers) {
+ // 设置建造状态为初始化中
+ buildState = BuildState.INITIALIZING;
+
+ // 进行初始化前的工作
+ beforeInit();
+ // 初始化
+ init();
+
+ // 设置建造状态为配置中
+ buildState = BuildState.CONFIGURING;
+
+ // 配置前的工作
+ beforeConfigure();
+ // 调用配置
+ configure();
+
+ // 设置建造状态为建造中
+ buildState = BuildState.BUILDING;
+
+ // 执行建造核心逻辑
+ O result = performBuild();
+
+ // 设置建造状态为已建造
+ buildState = BuildState.BUILT;
+
+ return result;
+ }
+ }
+
+```
+beforeInit()和beforeConfigure()是一个空方法体,没有逻辑。
+```
+ protected void beforeInit() throws Exception {
+ }
+ protected void beforeConfigure() throws Exception {
+ }
+```
+
+```
+ private void init() throws Exception {
+ // 调用getConfigurers()方法获取this.configurers的所有value值,并以List集合的形式返回
+ Collection> configurers = getConfigurers();
+ // 遍历configurers,并依次调用安全配置类的init方法
+ for (SecurityConfigurer configurer : configurers) {
+ // 调用安全配置类的init初始化方法
+ configurer.init((B) this);
+ }
+
+ for (SecurityConfigurer configurer : configurersAddedInInitializing) {
+ configurer.init((B) this);
+ }
+ }
+```
+
+这需要注意的是,init和configure方法是有接口SecurityConfigurer接口定义的,但其实现以由SecurityConfigurerAdapter这个抽象的适配器类实现了,所以最终的安全配置类可重写init()和configure(),也可以不重写。所以可以发现,很多安全配置类是没有重写init()方法的。
+
+
+**接着就是configure()方法的调用**
+
+```
+ private void configure() throws Exception {
+ // 调用getConfigurers()方法获取this.configurers的所有value值,并以List集合的形式返回
+ Collection> configurers = getConfigurers();
+
+ for (SecurityConfigurer configurer : configurers) {
+ // 遍历configurers,然后依次调用其configure方法
+ configurer.configure((B) this);
+ }
+ }
+```
+
+在前面已经已经以ExpressionUrlAuthorizationConfigurer为例,去查看安全配置类configure方法的作用,都知道安全配置类的configure方法是用于将过滤器添加到sharedObject缓存中。
+
+经过init()和configure()方法的执行,以及可以开始进行建造工作了,因而调用performBuild()方法执行建造过程。
+
+```
+ protected abstract O performBuild() throws Exception;
+```
+可以看到在AbstractConfiguredSecurityBuilder中,performBuild是以抽象方法的形式存在的,所以实现逻辑都在其子类中。
+
+
+
+这里HttpSecurity和WebSecurity类名这么像,有什么异同呢?
+
+> HttpSecurity
+
+HttpSecurity允许为特定的http请求配置基于Web的安全特性。默认情况下,HttpSecurity将应用于所有请求,但是如果需要限制请求,则可以通过RequestMatcher或其他类似方法来进行限制。
+
+> WebSecurity
+
+而WebSecurity是通过WebSecurityConfiguration创建的,用于去创建类FilterChainProxy。在SpringSecurity中,WebSecurity通过HttpSecurity来对某些请求进行拦截限制。
+
+> 区别
+
+WebSecurity用于建造FilterChainProxy,WebSecurity是包含HttpSecurity的一个更大的概念,而HttpSecurity仅是用于建造FilterChainProxy中的一个SecurityFilterChain。
+
+
+### 3. WebSecurity中的performBuild()方法
+WebSecurity重写了AbstractConfiguredSecurityBuilder的perfomBuild()方法,核心逻辑如下:
+
+```
+ @Override
+ protected Filter performBuild() throws Exception {
+ Assert.state(
+ !securityFilterChainBuilders.isEmpty(),
+ () -> "At least one SecurityBuilder extends SecurityFilterChain> needs to be specified. "
+ + "Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
+ + "More advanced users can invoke "
+ + WebSecurity.class.getSimpleName()
+ + ".addSecurityFilterChainBuilder directly");
+ // 获取chain大小
+ int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
+ // 设置安全过滤器链集合
+ List securityFilterChains = new ArrayList<>(
+ chainSize);
+ // 遍历igoredRequests集合,该集合表示存储着忽略拦截的请求
+ for (RequestMatcher ignoredRequest : ignoredRequests) {
+ securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
+ }
+ for (SecurityBuilder extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
+ // 先调用securityFilterChainBuilder执行build()方法,然后添加进securityFilterChains集合中。之列build()方法是去迭代执行doBuild()逻辑。
+ securityFilterChains.add(securityFilterChainBuilder.build());
+ }
+
+ // 创建一个FilterChainProxy对象,传入一个securityFilterChains对象
+ FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
+ if (httpFirewall != null) {
+ // 设置http防火墙属性
+ filterChainProxy.setFirewall(httpFirewall);
+ }
+ filterChainProxy.afterPropertiesSet();
+
+ Filter result = filterChainProxy;
+ if (debugEnabled) {
+ logger.warn("\n\n"
+ + "********************************************************************\n"
+ + "********** Security debugging is enabled. *************\n"
+ + "********** This may include sensitive information. *************\n"
+ + "********** Do not use in a production system! *************\n"
+ + "********************************************************************\n\n");
+ result = new DebugFilter(filterChainProxy);
+ }
+
+ // 执行一个线程
+ postBuildAction.run();
+ return result;
+ }
+
+```
+
+在performBuild()方法中,会执行securityFilterChainBuilder的build()方法,该方法又会去迭代执行doBuild()方法,最终返回一个SecurityFilterChain对象。
+
+
+综上,本文对WebSecurity的建造逻辑进行了概括性的讲解,更加深入的内容还需要进行代码debug跟踪深入查看,这样才能加深对于WebSecurity的理解。
+
+## 总结
+- 安全配置类是在HttpSecurity、XXConfigurerAdapter等类中进行添加
+- WebSecurity和HttpSecurity区别在于,WebSecurity是用于建造FilterChainProxy的,它是包含HttpSecurity;而HttpSecurity是用于对请求进行限制,同时还用于建造DefaultSecurityFilterChain
+- 安全配置类主要是通过configure方法向sharedObject缓存对象中添加过滤器,并最终添加进FilterChainProxy过滤器链中
+- WebSecurity建造FilterChainProxy的核心逻辑可以笼统的分为三步:安全配置了初始化、安全配置类configure的调用、performBuild的调用
+
+## 相关文章
+- [从零开始系统学习SpringSecurity和OAuth2(一)—— 初识SpringSecurity](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/SpringSecurity/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0SpringSecurity%E5%92%8COAuth2%EF%BC%88%E4%B8%80%EF%BC%89%E2%80%94%E2%80%94%20%E5%88%9D%E8%AF%86SpringSecurity.md)
+- [从零开始系统学习SpringSecurity和OAuth2(二)—— 安全过滤器FilterChainProxy](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/SpringSecurity/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0SpringSecurity%E5%92%8COAuth2%EF%BC%88%E4%BA%8C%EF%BC%89%E2%80%94%E2%80%94%20%E5%AE%89%E5%85%A8%E8%BF%87%E6%BB%A4%E5%99%A8FilterChainProxy.md)
\ No newline at end of file
diff --git "a/Spring-Security/src/main/doc/SpringSecurity/SpringSecurity\345\222\214OAuth2\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224 \345\256\211\345\205\250\350\277\207\346\273\244\345\231\250FilterChainProxy.md" "b/Spring-Security/src/main/doc/SpringSecurity/SpringSecurity\345\222\214OAuth2\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224 \345\256\211\345\205\250\350\277\207\346\273\244\345\231\250FilterChainProxy.md"
new file mode 100644
index 0000000..f3d7189
--- /dev/null
+++ "b/Spring-Security/src/main/doc/SpringSecurity/SpringSecurity\345\222\214OAuth2\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224 \345\256\211\345\205\250\350\277\207\346\273\244\345\231\250FilterChainProxy.md"
@@ -0,0 +1,370 @@
+- [前言](#前言)
+- [正文](#正文)
+ - [1. FilterChainProxy什么时候注入Spring容器中的](#1--filterchainproxy什么时候注入spring容器中的)
+ - [2. WebSecurityConfiguration类](#2-websecurityconfiguration类)
+ - [3. WebSecurity类](#3-websecurity类)
+ - [4. AbstractConfiguredSecurityBuilder类](#4-abstractconfiguredsecuritybuilder类)
+ - [5. SecurityConfigurer类](#5-securityconfigurer类)
+ - [6. doBuild()方法](#6-dobuild方法)
+ - [7. WebSecurity什么时候被创建的?](#7-websecurity什么时候被创建的)
+- [总结](#总结)
+- [参考](#参考)
+- [相关文章](#相关文章)
+
+
+## 前言
+相信了解过SpringSecurity或者是OAuth2的读者,会发现网上会有非常多的相关文章,或是纯概念的,或是带有demo的,无论是哪种类型的文章,本人去阅读之后,对于整个框架的概念还是一知半解,也仅仅是实现了某些功能、某些效果而已,若遇到某些问题时无从下手,只能去百度去Google。这是因为对于SpringSecurity和OAuth2的知识没有一个整体概念的把握,知识体系没有形成系统,遂决定写一个关于SpringSecurity和OAuth2的系列专栏,在建造自己知识体系的同时还希望能帮助有同样困惑的同学。
+
+**本专栏希望通过通俗易懂的语言来达到从入门概念、demo开始,由简入深,最终能达到深谙其底层源码的目的。**
+
+============== 分割线 ==============
+
+上篇文章粗略的讲解了SpringSecurity里的几个核心概念,本篇文章就来深扒一下安全过滤器FilterChainProxy的底层原理。
+
+## 正文
+### 1. FilterChainProxy什么时候注入Spring容器中的
+在SpringSecurity中,FilterChainProxy是作为整个框架的核心,它是一个过滤器。在SpringSecurity中,一个过滤器名字叫springSecurityFilterChain,它的类型就是FilterChainProxy。
+
+在@EnableWebSecurity注解中,@Import了一个关键类:WebSecurityConfiguration。
+
+首先,WebSecurityConfiguration实现了ImportAware和BeanClassLoaderAware接口,分别实现了setImportMetadata()和setBeanClassLoader()
+
+setImportMetadata()方法的作用是注入注解元数据。
+```
+ public void setImportMetadata(AnnotationMetadata importMetadata) {
+ // 从注入的importMetadata中获取@EnableWebSecurity注解map值
+ Map enableWebSecurityAttrMap = importMetadata
+ .getAnnotationAttributes(EnableWebSecurity.class.getName());
+ // 将map值封装成AnnotationAttributes
+ AnnotationAttributes enableWebSecurityAttrs = AnnotationAttributes
+ .fromMap(enableWebSecurityAttrMap);
+ // 从AnnotationAttributes中获取debug属性值
+ debugEnabled = enableWebSecurityAttrs.getBoolean("debug");
+ if (webSecurity != null) {
+ // 将debugEnabled存到WebSecurity属性中
+ webSecurity.debug(debugEnabled);
+ }
+ }
+```
+setBeanClassLoader方法作用就是注入类加载器ClassLoader。
+```
+ public void setBeanClassLoader(ClassLoader classLoader) {
+ this.beanClassLoader = classLoader;
+ }
+```
+
+废话不多说,看下FilterChainProxy是什么时候注入到Spring容器中的。
+
+答案就在WebSecurityConfiguration的springSecurityFilterChain()方法中
+
+```
+ // AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME的值是:springSecurityFilterChain
+ // 所以springSecurityFilterChain()的作用就是想Spring容器中注入一个名为springSecurityChain的bean。
+ @Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
+ public Filter springSecurityFilterChain() throws Exception {
+ // 判断是否有webSecurityConfigurers
+ boolean hasConfigurers = webSecurityConfigurers != null
+ && !webSecurityConfigurers.isEmpty();
+ // 如果没有配置,则通过objectObjectPostProcessor来生成一个新的WebSecurityConfigurerAdapter
+ if (!hasConfigurers) {
+ WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
+ .postProcess(new WebSecurityConfigurerAdapter() {
+ });
+ webSecurity.apply(adapter);
+ }
+ return webSecurity.build();
+ }
+```
+
+### 2. WebSecurityConfiguration类
+在深入springSecurityFilterChain()方法底层原理之前,需要先了解WebSecurityConfiguration中几个重要的成员变量。
+```
+@Configuration
+public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
+
+ // WebSecurity是用于建造FilterChainProxy过滤器的核心类
+ private WebSecurity webSecurity;
+
+ // 读取@EnableWebSecurity中的注解属性debugEnabled的值
+ private Boolean debugEnabled;
+
+ // SecurityConfigurer属性值集合
+ private List> webSecurityConfigurers;
+
+ // 类加载器
+ private ClassLoader beanClassLoader;
+
+ // 省略
+}
+```
+
+### 3. WebSecurity类
+第一个重要的类就是WebSecurity。
+
+由WebSecurity的类注释可以了解到:
+
+- WebSecurity是由WebSecurityConfiguration创建的,用于创建FilterChainProxy
+- FilterChainProxy在SpringSecurity中,以springSecurityFilterChainProxy的bean名称暴露于容器之中的
+- 可以通过基础抽象类WebSecurityConfigurerAdapter来定制化WebSecurity
+
+由于@EnableWebSecurity导入了WebSecurityConfiguration,因而WebSecurity也被创建。
+
+我们先来看下WebSecurity的类结构:
+
+```
+public final class WebSecurity extends
+ AbstractConfiguredSecurityBuilder implements
+ SecurityBuilder, ApplicationContextAware {
+ // 省略
+}
+```
+
+首先,WebSecurity是一个final修饰的类,即该类:
+
+- 不能被继承,没有子类
+- 该类方法都为final
+
+其次,WebSecurity继承了AbstractConfiguredSecurityBuilder。继续跟进看下AbstractConfiguredSecurityBuilder这个类有什么作用?
+
+### 4. AbstractConfiguredSecurityBuilder类
+由其类名:AbstractConfiguredSecurityBuilder就可以知道,该类是一个抽象类,作为抽象类,必然会抽象出abstract方法让子类去实现。浏览AbstractConfiguredSecurityBuilder的方法定义,可以看到它内部只定义了一个抽象方法:
+```
+protected abstract O performBuild() throws Exception;
+```
+
+这个方法会在建造FilterChainProxy时有使用到,这里先留个印象。
+
+回到AbstractConfiguredSecurityBuilder类定义
+```
+public abstract class AbstractConfiguredSecurityBuilder>
+ extends AbstractSecurityBuilder {
+ // 省略
+}
+```
+可以知道它继承了AbstractSecurityBuilder,但自身带的一个泛型>让人捉摸不透是啥意思。O是啥?B又是啥?
+
+这里其实是用到了**建造者模式**。
+
+目光聚焦到SecurityBuilder这个接口
+
+```
+// 安全建造者
+// 顾名思义是一个builder建造者,创建并返回一个类型为O的对象
+public interface SecurityBuilder {
+ O build() throws Exception;
+}
+```
+
+```
+// 抽象安全建造者
+public abstract class AbstractSecurityBuilder implements SecurityBuilder {
+ private AtomicBoolean building = new AtomicBoolean();
+ private O object;
+
+ // build建造方法被final修饰,不允许子类覆盖。
+ public final O build() throws Exception {
+ if (this.building.compareAndSet(false, true)) {
+ this.object = doBuild();
+ return this.object;
+ }
+ throw new AlreadyBuiltException("This object has already been built");
+ }
+
+ // 子类需要重写doBuild()方法
+ protected abstract O doBuild() throws Exception;
+}
+```
+所以B extends SecurityBuilder就是指B是SecurityBuilder的子类,用于建造O。
+
+从WebSecurity中的类定义可以发现
+```
+AbstractConfiguredSecurityBuilder
+```
+
+AbstractConfiguredSecurityBuilder作用就是通过WebSecurity这个建造者建造出一个Filter,而这个Filter就是FilterChainProxy。
+
+**因此O就是指FilterChainProxy,B就是指的安全建造者WebSecurity。**
+
+
+
+再来看下AbstractConfiguredSecurityBuilder的成员变量。
+
+```
+public abstract class AbstractConfiguredSecurityBuilder>
+ extends AbstractSecurityBuilder {
+ private final Log logger = LogFactory.getLog(getClass());
+
+ // 安全配置器的子类集合,这个configurers就是用于初始化以及配置FilterChainProxy中的filters用的
+ private final LinkedHashMap>, List>> configurers = new LinkedHashMap<>();
+ // 初始化期间添加的配置类
+ private final List> configurersAddedInInitializing = new ArrayList<>();
+ // 缓存
+ private final Map, Object> sharedObjects = new HashMap<>();
+
+ private final boolean allowConfigurersOfSameType;
+
+ // 建造者的建造状态,初始状态为:未建造
+ private BuildState buildState = BuildState.UNBUILT;
+
+ // 用于生成bean
+ private ObjectPostProcessor