深入理解 WebSecurityConfigurerAdapter【源码篇】(1),毕业设计软件技术


我们来看下 WebSecurity 的定义:

public final class WebSecurity extends

AbstractConfiguredSecurityBuilder<Filter, WebSecurity> implements

SecurityBuilder, ApplicationContextAware {

}

没错,确实是这样!WebSecurity 继承自 AbstractConfiguredSecurityBuilder<Filter, WebSecurity> 同时实现了 SecurityBuilder 接口。

WebSecurity 的这些接口和继承类,松哥在前面的源码分析中都和大家介绍过了,可能有的小伙伴忘记了,我再来和大家复习一下。

AbstractConfiguredSecurityBuilder

首先 AbstractConfiguredSecurityBuilder 中定义了一个枚举类,将整个构建过程分为 5 种状态,也可以理解为构建过程生命周期的五个阶段,如下:

private enum BuildState {

UNBUILT(0),

INITIALIZING(1),

CONFIGURING(2),

BUILDING(3),

BUILT(4);

private final int order;

BuildState(int order) {

this.order = order;

}

public boolean isInitializing() {

return INITIALIZING.order == order;

}

public boolean isConfigured() {

return order >= CONFIGURING.order;

}

}

五种状态分别是 UNBUILT、INITIALIZING、CONFIGURING、BUILDING 以及 BUILT。另外还提供了两个判断方法,isInitializing 判断是否正在初始化,isConfigured 表示是否已经配置完毕。

AbstractConfiguredSecurityBuilder 中的方法比较多,松哥在这里列出来两个关键的方法和大家分析:

private <C extends SecurityConfigurer<O, B>> void add(C configurer) {

Assert.notNull(configurer, “configurer cannot be null”);

Class<? extends SecurityConfigurer<O, B>> clazz = (Class<? extends SecurityConfigurer<O, B>>) configurer

.getClass();

synchronized (configurers) {

if (buildState.isConfigured()) {

throw new IllegalStateException("Cannot apply " + configurer

  • " to already built object");

}

List<SecurityConfigurer<O, B>> configs = allowConfigurersOfSameType ? this.configurers

.get(clazz) : null;

if (configs == null) {

configs = new ArrayList<>(1);

}

configs.add(configurer);

this.configurers.put(clazz, configs);

if (buildState.isInitializing()) {

this.configurersAddedInInitializing.add(configurer);

}

}

}

private Collection<SecurityConfigurer<O, B>> getConfigurers() {

List<SecurityConfigurer<O, B>> result = new ArrayList<>();

for (List<SecurityConfigurer<O, B>> configs : this.configurers.values()) {

result.addAll(configs);

}

return result;

}

第一个就是这个 add 方法,这相当于是在收集所有的配置类。将所有的 xxxConfigure 收集起来存储到 configurers 中,将来再统一初始化并配置,configurers 本身是一个 LinkedHashMap ,key 是配置类的 class,value 是一个集合,集合里边放着 xxxConfigure 配置类。当需要对这些配置类进行集中配置的时候,会通过 getConfigurers 方法获取配置类,这个获取过程就是把 LinkedHashMap 中的 value 拿出来,放到一个集合中返回。

另一个方法就是 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;

}

}

private void init() throws Exception {

Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();

for (SecurityConfigurer<O, B> configurer : configurers) {

configurer.init((B) this);

}

for (SecurityConfigurer<O, B> configurer : configurersAddedInInitializing) {

configurer.init((B) this);

}

}

private void configure() throws Exception {

Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();

for (SecurityConfigurer<O, B> configurer : configurers) {

configurer.configure((B) this);

}

}

在 AbstractSecurityBuilder 类中,过滤器的构建被转移到 doBuild 方法上面了,不过在 AbstractSecurityBuilder 中只是定义了抽象的 doBuild 方法,具体的实现在 AbstractConfiguredSecurityBuilder。

doBuild 方法就是一边更新状态,进行进行初始化。

beforeInit 是一个预留方法,没有任何实现。

init 方法就是找到所有的 xxxConfigure,挨个调用其 init 方法进行初始化。

beforeConfigure 是一个预留方法,没有任何实现。

configure 方法就是找到所有的 xxxConfigure,挨个调用其 configure 方法进行配置。

最后则是 performBuild 方法,是真正的过滤器链构建方法,但是在 AbstractConfiguredSecurityBuilder 中 performBuild 方法只是一个抽象方法,具体的实现在它的子类中,也就是 WebSecurityConfigurer。

SecurityBuilder

SecurityBuilder 就是用来构建过滤器链的,在 HttpSecurity 实现 SecurityBuilder 时,传入的泛型就是 DefaultSecurityFilterChain,所以 SecurityBuilder#build 方法的功能很明确,就是用来构建一个过滤器链出来,但是那个过滤器链是 Spring Security 中的。在 WebSecurityConfigurerAdapter 中定义的泛型是 SecurityBuilder,所以最终构建的是一个普通 Filter,其实就是 FilterChainProxy,关于 FilterChainProxy ,大家可以参考深入理解 FilterChainProxy【源码篇】

WebSecurity

WebSecurity 的核心逻辑集中在 performBuild 构建方法上,我们一起来看下:

@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”);

int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();

List securityFilterChains = new ArrayList<>(

chainSize);

for (RequestMatcher ignoredRequest : ignoredRequests) {

securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));

}

for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {

securityFilterChains.add(securityFilterChainBuilder.build());

}

FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);

if (httpFirewall != null) {

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 方法只有一个功能,那就是构建 FilterChainProxy,如果你还不了解什么是 FilterChainProxy,可以参考松哥之前的介绍:深入理解 FilterChainProxy【源码篇】

把握住了这条主线,我们再来看方法的实现就很容易了。

  1. 首先统计过滤器链的总条数,总条数包括两个方面,一个是 ignoredRequests,这是忽略的请求,通过 WebSecurity 配置的忽略请求,松哥之前介绍过,参见:Spring Security 两种资源放行策略,千万别用错了!,另一个则是 securityFilterChainBuilders,也就是我们通过 HttpSecurity 配置的过滤器链,有几个就算几个。

  2. 创建 securityFilterChains 集合,并且遍历上面提到的两种类型的过滤器链,并将过滤器链放入 securityFilterChains 集合中。

  3. 我在深入理解 HttpSecurity【源码篇】一文中介绍过,HttpSecurity 构建出来的过滤器链对象就是 DefaultSecurityFilterChain,所以可以直接将 build 结果放入 securityFilterChains 中,而 ignoredRequests 中保存的则需要重构一下才可以存入 securityFilterChains。

  4. securityFilterChains 中有数据之后,接下来创建一个 FilterChainProxy。

  5. 给新建的 FilterChainProxy 配置上防火墙,防火墙的介绍参考松哥之前的:Spring Security 自带防火墙!你都不知道自己的系统有多安全!

  6. 最后我们返回的就是 FilterChainProxy 的实例。

从这段分析中,我们可以看出来 WebSecurity 和 HttpSecurity 的区别:

  1. HttpSecurity 目的是构建过滤器链,一个 HttpSecurity 对象构建一条过滤器链,一个过滤器链中有 N 个过滤器,HttpSecurity 所做的事情实际上就是在配置这 N 个过滤器。

  2. WebSecurity 目的是构建 FilterChainProxy,一个 FilterChainProxy 中包含有多个过滤器链和一个 Firewall。

这就是 WebSecurity 的主要作用,核心方法是 performBuild,其他方法都比较简单,松哥就不一一解释了。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数同学面临毕业设计项目选题时,很多人都会感到无从下手,尤其是对于计算机专业的学生来说,选择一个合适的题目尤为重要。因为毕业设计不仅是我们在大学四年学习的一个总结,更是展示自己能力的重要机会。

因此收集整理了一份《2024年计算机毕业设计项目大全》,初衷也很简单,就是希望能够帮助提高效率,同时减轻大家的负担。
img
img
img

既有Java、Web、PHP、也有C、小程序、Python等项目供你选择,真正体系化!

由于项目比较多,这里只是将部分目录截图出来,每个节点里面都包含素材文档、项目源码、讲解视频

如果你觉得这些内容对你有帮助,可以添加VX:vip1024c (备注项目大全获取)
img

结,更是展示自己能力的重要机会。**

因此收集整理了一份《2024年计算机毕业设计项目大全》,初衷也很简单,就是希望能够帮助提高效率,同时减轻大家的负担。
[外链图片转存中…(img-5xMafGxb-1712584380477)]
[外链图片转存中…(img-ruwepGRw-1712584380478)]
[外链图片转存中…(img-8r7SU0mf-1712584380479)]

既有Java、Web、PHP、也有C、小程序、Python等项目供你选择,真正体系化!

由于项目比较多,这里只是将部分目录截图出来,每个节点里面都包含素材文档、项目源码、讲解视频

如果你觉得这些内容对你有帮助,可以添加VX:vip1024c (备注项目大全获取)
[外链图片转存中…(img-CbtU11FO-1712584380479)]

  • 23
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值