1
- @[ toc]
1
+ <!-- TOC -->
2
+ - [ 前言] ( #前言 )
3
+ - [ 正文] ( #正文 )
4
+ - [ 1. AbstractConfiguredSecurityBuilder中安全配置类] ( #1-abstractconfiguredsecuritybuilder中安全配置类 )
5
+ - [2. AbstractConfiguredSecurityBuilder的doBuild()方法](#2-abstractconfiguredsecuritybuilder的dobuild方法)
6
+ - [3. WebSecurity中的performBuild()方法](#3-websecurity中的performbuild方法)
7
+ - [ 总结] ( #总结 )
8
+ - [ 相关文章] ( #相关文章 )
9
+ <!-- /TOC -->
2
10
## 前言
3
11
相信了解过SpringSecurity或者是OAuth2的读者,会发现网上会有非常多的相关文章,或是纯概念的,或是带有demo的,无论是哪种类型的文章,本人去阅读之后,对于整个框架的概念还是一知半解,也仅仅是实现了某些功能、某些效果而已,若遇到某些问题时无从下手,只能去百度去Google。这是因为对于SpringSecurity和OAuth2的知识没有一个整体概念的把握,知识体系没有形成系统,遂决定写一个关于SpringSecurity和OAuth2的系列专栏,在建造自己知识体系的同时还希望能帮助有同样困惑的同学。
4
12
9
17
## 正文
10
18
11
19
### 1. AbstractConfiguredSecurityBuilder中安全配置类
12
- SpringSecurity通过SecurityConfigurer来构建FilterChainProxy,构建前还需要进行配置 。因此AbstractConfiguredSecurityBuilder还需要注入配置组件SecurityConfigurer,初始化配置组件SecurityConfigurer,调用SecurityConfigurer的configure方法。
20
+ SpringSecurity通过SecurityConfigurer来建造FilterChainProxy,建造前还需要进行配置 。因此AbstractConfiguredSecurityBuilder还需要注入配置组件SecurityConfigurer,初始化配置组件SecurityConfigurer,调用SecurityConfigurer的configure方法。
13
21
14
22
在AbstractConfiguredSecurityBuilder类中,看下安全配置类的定义:‘
15
23
@@ -28,7 +36,7 @@ private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<Secu
28
36
.getClass();
29
37
// 同步去操作安全配置类集合
30
38
synchronized (configurers) {
31
- // 查看构建状态是否是已经配置
39
+ // 查看建造状态是否是已经配置
32
40
if (buildState.isConfigured()) {
33
41
throw new IllegalStateException("Cannot apply " + configurer
34
42
+ " to already built object");
@@ -62,7 +70,7 @@ private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<Secu
62
70
throws Exception {
63
71
// 传入objectPostProcessor,该对象用于创建各种“实例”,具体什么作用下问会讲解,请留意
64
72
configurer.addObjectPostProcessor(objectPostProcessor);
65
- // 将当前对象设置为构建者
73
+ // 将当前对象设置为建造者
66
74
configurer.setBuilder((B) this);
67
75
// 调用add方法,向configurers集合中添加configurer
68
76
add(configurer);
@@ -128,35 +136,35 @@ getOrApply方法主要是从configurers集合中获取配置类,如果存在
128
136
到此处,安全配置类的作用已经提现出来了,就是向sharedObject中添加过滤器,并最终注入到FilterChainProxy中。
129
137
130
138
### 2. AbstractConfiguredSecurityBuilder的doBuild()方法
131
- 随着configurers集合元素的注入,下面就是进行构建工作 ,调用doBuild()方法。
139
+ 随着configurers集合元素的注入,下面就是进行建造工作 ,调用doBuild()方法。
132
140
133
141
```
134
142
@Override
135
143
protected final O doBuild() throws Exception {
136
144
synchronized (configurers) {
137
- // 设置构建状态为初始化中
145
+ // 设置建造状态为初始化中
138
146
buildState = BuildState.INITIALIZING;
139
147
140
148
// 进行初始化前的工作
141
149
beforeInit();
142
150
// 初始化
143
151
init();
144
152
145
- // 设置构建状态为配置中
153
+ // 设置建造状态为配置中
146
154
buildState = BuildState.CONFIGURING;
147
155
148
156
// 配置前的工作
149
157
beforeConfigure();
150
158
// 调用配置
151
159
configure();
152
160
153
- // 设置构建状态为构建中
161
+ // 设置建造状态为建造中
154
162
buildState = BuildState.BUILDING;
155
163
156
- // 执行构建核心逻辑
164
+ // 执行建造核心逻辑
157
165
O result = performBuild();
158
166
159
- // 设置构建状态为已构建
167
+ // 设置建造状态为已建造
160
168
buildState = BuildState.BUILT;
161
169
162
170
return result;
@@ -188,6 +196,113 @@ beforeInit()和beforeConfigure()是一个空方法体,没有逻辑。
188
196
}
189
197
```
190
198
191
- 这需要注意的是,init和configure方法是有接口SecurityConfigurer接口定义的,但其实现以由SecurityConfigurerAdapter这个抽象的适配器类实现了,所以最终的安全配置类可重写init()和configure(),也可以不重写。所以可以发现,很多安全配置类是重写没有init ()方法的。
199
+ 这需要注意的是,init和configure方法是有接口SecurityConfigurer接口定义的,但其实现以由SecurityConfigurerAdapter这个抽象的适配器类实现了,所以最终的安全配置类可重写init()和configure(),也可以不重写。所以可以发现,很多安全配置类是没有重写init ()方法的。
192
200
193
- 未完待续....
201
+
202
+ ** 接着就是configure()方法的调用**
203
+
204
+ ```
205
+ private void configure() throws Exception {
206
+ // 调用getConfigurers()方法获取this.configurers的所有value值,并以List集合的形式返回
207
+ Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
208
+
209
+ for (SecurityConfigurer<O, B> configurer : configurers) {
210
+ // 遍历configurers,然后依次调用其configure方法
211
+ configurer.configure((B) this);
212
+ }
213
+ }
214
+ ```
215
+
216
+ 在前面已经已经以ExpressionUrlAuthorizationConfigurer为例,去查看安全配置类configure方法的作用,都知道安全配置类的configure方法是用于将过滤器添加到sharedObject缓存中。
217
+
218
+ 经过init()和configure()方法的执行,以及可以开始进行建造工作了,因而调用performBuild()方法执行建造过程。
219
+
220
+ ```
221
+ protected abstract O performBuild() throws Exception;
222
+ ```
223
+ 可以看到在AbstractConfiguredSecurityBuilder中,performBuild是以抽象方法的形式存在的,所以实现逻辑都在其子类中。
224
+
225
+ ![ 在这里插入图片描述] ( https://img-blog.csdnimg.cn/20200810112226524.png )
226
+
227
+ 这里HttpSecurity和WebSecurity类名这么像,有什么异同呢?
228
+
229
+ > HttpSecurity
230
+
231
+ HttpSecurity允许为特定的http请求配置基于Web的安全特性。默认情况下,HttpSecurity将应用于所有请求,但是如果需要限制请求,则可以通过RequestMatcher或其他类似方法来进行限制。
232
+
233
+ > WebSecurity
234
+
235
+ 而WebSecurity是通过WebSecurityConfiguration创建的,用于去创建类FilterChainProxy。在SpringSecurity中,WebSecurity通过HttpSecurity来对某些请求进行拦截限制。
236
+
237
+ > 区别
238
+
239
+ WebSecurity用于建造FilterChainProxy,WebSecurity是包含HttpSecurity的一个更大的概念,而HttpSecurity仅是用于建造FilterChainProxy中的一个SecurityFilterChain。
240
+
241
+
242
+ ### 3. WebSecurity中的performBuild()方法
243
+ WebSecurity重写了AbstractConfiguredSecurityBuilder的perfomBuild()方法,核心逻辑如下:
244
+
245
+ ```
246
+ @Override
247
+ protected Filter performBuild() throws Exception {
248
+ Assert.state(
249
+ !securityFilterChainBuilders.isEmpty(),
250
+ () -> "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. "
251
+ + "Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
252
+ + "More advanced users can invoke "
253
+ + WebSecurity.class.getSimpleName()
254
+ + ".addSecurityFilterChainBuilder directly");
255
+ // 获取chain大小
256
+ int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
257
+ // 设置安全过滤器链集合
258
+ List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
259
+ chainSize);
260
+ // 遍历igoredRequests集合,该集合表示存储着忽略拦截的请求
261
+ for (RequestMatcher ignoredRequest : ignoredRequests) {
262
+ securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
263
+ }
264
+ for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
265
+ // 先调用securityFilterChainBuilder执行build()方法,然后添加进securityFilterChains集合中。之列build()方法是去迭代执行doBuild()逻辑。
266
+ securityFilterChains.add(securityFilterChainBuilder.build());
267
+ }
268
+
269
+ // 创建一个FilterChainProxy对象,传入一个securityFilterChains对象
270
+ FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
271
+ if (httpFirewall != null) {
272
+ // 设置http防火墙属性
273
+ filterChainProxy.setFirewall(httpFirewall);
274
+ }
275
+ filterChainProxy.afterPropertiesSet();
276
+
277
+ Filter result = filterChainProxy;
278
+ if (debugEnabled) {
279
+ logger.warn("\n\n"
280
+ + "********************************************************************\n"
281
+ + "********** Security debugging is enabled. *************\n"
282
+ + "********** This may include sensitive information. *************\n"
283
+ + "********** Do not use in a production system! *************\n"
284
+ + "********************************************************************\n\n");
285
+ result = new DebugFilter(filterChainProxy);
286
+ }
287
+
288
+ // 执行一个线程
289
+ postBuildAction.run();
290
+ return result;
291
+ }
292
+
293
+ ```
294
+
295
+ 在performBuild()方法中,会执行securityFilterChainBuilder的build()方法,该方法又会去迭代执行doBuild()方法,最终返回一个SecurityFilterChain对象。
296
+
297
+
298
+ 综上,本文对WebSecurity的建造逻辑进行了概括性的讲解,更加深入的内容还需要进行代码debug跟踪深入查看,这样才能加深对于WebSecurity的理解。
299
+
300
+ ## 总结
301
+ - 安全配置类是在HttpSecurity、XXConfigurerAdapter等类中进行添加
302
+ - WebSecurity和HttpSecurity区别在于,WebSecurity是用于建造FilterChainProxy的,它是包含HttpSecurity;而HttpSecurity是用于对请求进行限制,同时还用于建造DefaultSecurityFilterChain
303
+ - 安全配置类主要是通过configure方法向sharedObject缓存对象中添加过滤器,并最终添加进FilterChainProxy过滤器链中
304
+ - WebSecurity建造FilterChainProxy的核心逻辑可以笼统的分为三步:安全配置了初始化、安全配置类configure的调用、performBuild的调用
305
+
306
+ ## 相关文章
307
+ - [ 从零开始系统学习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 )
308
+ - [ 从零开始系统学习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 )
0 commit comments