2024年Web前端最新深入理解 WebSecurityConfigurerAdapter【源码篇】,BAT面试&高级进阶

2301_82243626 2024-06-28 16:33:04 阅读 89

最后

一个好的心态和一个坚持的心很重要,很多冲着高薪的人想学习前端,但是能学到最后的没有几个,遇到困难就放弃了,这种人到处都是,就是因为有的东西难,所以他的回报才很大,我们评判一个前端开发者是什么水平,就是他解决问题的能力有多强。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

分享一些前端面试题以及学习路线给大家

所以关于这两个类的介绍以及作用,松哥这里就不赘述了。咱们直接从 WebSecurityConfigurer 开始看起。

1.WebSecurityConfigurer


WebSecurityConfigurer 其实是一个空接口,但是它里边约束了一些泛型,如下:

public interface WebSecurityConfigurer<T extends SecurityBuilder> extends

SecurityConfigurer<Filter, T> {

}

这里边的泛型很关键,这关乎到 WebSecurityConfigurer 的目的是啥!

SecurityBuilder 中的泛型 Filter,表示 SecurityBuilder 最终的目的是为了构建一个 Filter 对象出来。

SecurityConfigurer 中两个泛型,第一个表示的含义也是 SecurityBuilder 最终构建的对象。

同时这里还定义了新的泛型 T,T 需要继承自 SecurityBuilder,根据 WebSecurityConfigurerAdapter 中的定义,我们可以知道,T 就是 WebSecurity,我们也大概能猜出 WebSecurity 就是 SecurityBuilder 的子类。

所以 WebSecurityConfigurer 的目的我们可以理解为就是为了配置 WebSecurity。

2.WebSecurity


我们来看下 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);

JavaScript 和 ES6

在这个过程你会发现,有很多 JS 知识点你并不能更好的理解为什么这么设计,以及这样设计的好处是什么,这就逼着让你去学习这单个知识点的来龙去脉,去哪学?第一,书籍,我知道你不喜欢看,我最近通过刷大厂面试题整理了一份前端核心知识笔记,比较书籍更精简,一句废话都没有,这份笔记也让我通过跳槽从8k涨成20k。

JavaScript部分截图

如果你觉得对你有帮助,可以戳这里获取:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

JavaScript 和 ES6

在这个过程你会发现,有很多 JS 知识点你并不能更好的理解为什么这么设计,以及这样设计的好处是什么,这就逼着让你去学习这单个知识点的来龙去脉,去哪学?第一,书籍,我知道你不喜欢看,我最近通过刷大厂面试题整理了一份前端核心知识笔记,比较书籍更精简,一句废话都没有,这份笔记也让我通过跳槽从8k涨成20k。

JavaScript部分截图

如果你觉得对你有帮助,可以戳这里获取:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。