httpSecurity 的执行流程和 AuthenticationConfiguration 配置的 AuthenticationManager
0x00 回顾
webSecurity, httpSecurity 和 AuthenticationManagerBuilder 都继承了 AbstractSecurityBuilder<O>,
也就是他们都是使用的设计模式里面的建造者模式各自创建的对象.
webSecurity 被 WebSecurityConfiguration 控制创建了过滤链的代理,
httpSecuity 被 webSecurity 控制创建了过滤链,
AuthenticationManagerBuilder 被 AuthenticationConfiguration 控制, 创建了 AuthenticationManager;
值得注意的是, 在建造者设计模式里面产品, 建造者, 指挥者的关系. 指挥者设置建造者里面的参数, 调用建造者的 build 方法获取产品对象.
在上篇讲的 webSecurity 里面, 这个关系是 :
webSecurityConfigutation 设置 webSecurity 的参数 (WebSecurityConfigurer<WebSecurity>),
调用 build() 方法获取 filterChainProxy 对象.
这都是在 webSecurityConfigutation 类里面完成的.
在接下来要讲的 httpSecurity 里面, 也是这个类似的关系, 只是流程不是这么典型 :
webSecurity#build()#init() 执行的时候, 调用了他里面的 webSecurityConfigutation 类的 init() 方法.
并将创建好的 httpSeurity 对象放在 securityFilterChainBuilder 集合里面.
此时创建了 httpSecurity 对象, 并且给 httpSecurity 对象设置了一些默认需要的过滤器配置,
这些过滤器配置会在 httpSecurity#build() 的时候创建过滤器并加入 filters 里面;
在 webSecurity#build()#perfromBuild() 里面才会对每一个 httpSecurity 执行 build() 方法,
获取 httpSecurity 创建的 DefaultSecurityFilterChain 对象.
至于 AuthenticationManagerBuilder 在 AuthenticationConfiguration 里面清纯简单不做作的被创建个鬼啊. / 扶额
AuthenticationManagerBuilder 根据用户的使用情况, 是否重载了 configure(AuthenticationManagerBuilder auth) 方法,
1. 没有重载就是在 AuthenticationConfiguration#getAuthenticationManager() 方法里被创建, 这样会注入一些 bean.
2. 重载了, 那就是在 WebSecurityConfigurer 里创建一个空的实例.
然后将 AuthenticationManager 设置进 httpSecurity 里, 当 httpSecurity 的配置文件执行 init() 方法的时候,
会根据这个 http_filter_configurer 配置文件的情况将 AuthenticationManagerBuilder 里设置配置值 (provider 的实现类).
最后在 beforeConfigure() 方法里 执行 build() 方法 构建 AuthenticationManager 实例.
0x01 从 WebSecurityConfigurerAdapter 里面的 getHttp() 开始
webSecurity#build()#init() 方法执行的时候, 调用 WebSecurityConfigurerAdapter 类的 init() 方法;
在 init() 里面 httpSecurity 被创建和初始化, 也被设置进 webSecurity;
// 不重要的方法略过
@Order(100)
public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigurer<WebSecurity> {
// 这几个变量关系比较明确, 建造者设计模式
private AuthenticationConfiguration authenticationConfiguration;
private AuthenticationManagerBuilder authenticationBuilder;
private AuthenticationManagerBuilder localConfigureAuthenticationBldr;
private AuthenticationManager authenticationManager;
public void init(final WebSecurity web) throws Exception {
// 初始化了一个 http 对象,
final HttpSecurity http = getHttp();
// 将 http 设置进 webSecurity.
web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() {
public void run() {
FilterSecurityInterceptor securityInterceptor = http.getSharedObject(FilterSecurityInterceptor.class);
web.securityInterceptor(securityInterceptor);
}
});
}
protected final HttpSecurity getHttp() throws Exception {
if (http != null) {
return http;
}
DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher());
localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
// 1, 这里获取鉴权管理
AuthenticationManager authenticationManager = authenticationManager();
// 设置在父级里面, 此变量也是在 setObjectPostProcessor() 方法里被赋值
authenticationBuilder.parentAuthenticationManager(authenticationManager);
// 2, 创建共享对象
Map<Class<? extends Object>, Object> sharedObjects = createSharedObjects();
// 创建了一个 http 实例
http = new HttpSecurity(objectPostProcessor, authenticationBuilder, sharedObjects);
// 这就是默认被配置的过滤器链, 配置的顺序在别的地方有排序
if (!disableDefaults) {
// @formatter:off
http
.csrf().and()
.addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling().and()
.headers().and()
.sessionManagement().and()
.securityContext().and()
.requestCache().and()
.anonymous().and()
.servletApi().and()
.apply(new DefaultLoginPageConfigurer<HttpSecurity>()).and()
.logout();
// @formatter:on
ClassLoader classLoader = this.context.getClassLoader();
// SpringFactoriesLoader 这个类实现了检索 META-INF/spring.factories 文件,并获取指定接口的配置的功能。
// 这是 java spi 的约定, 基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定
List<AbstractHttpConfigurer> defaultHttpConfigurers =
SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);
// 如果有, 则加入 http 配置类里面.
for(AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
http.apply(configurer);
}
}
// 调用被子类覆盖重写的方法, 这个方法也就是我们使用 spring security 的主要配置的方法啦
configure(http);
return http;
}
// 如果 #configure(AuthenticationManagerBuilder) 方法没被重载了, 就执行默认的 authenticationConfiguration;
// 否则执行 localConfigureAuthenticationBldr.build(); 来获取 AuthenticationManager;
protected AuthenticationManager authenticationManager() throws Exception {
if (!authenticationManagerInitialized) {
configure(localConfigureAuthenticationBldr);
if (disableLocalConfigureAuthenticationBldr) {
// authenticationConfiguration 此变量是直接被 spring ioc Autowire 设置的,
// 实例来自 AuthenticationConfiguration 的注入
authenticationManager = authenticationConfiguration.getAuthenticationManager();
} else {
// localConfigureAuthenticationBldr 看下面的方法
authenticationManager = localConfigureAuthenticationBldr.build();
}
authenticationManagerInitialized = true;
}
return authenticationManager;
}
// 这里就是 localConfigureAuthenticationBldr 被创建的时候, 也是直接 new 的
// 为什么要说也? 因为 AuthenticationConfiguration 也是这么创建的. 只是设置了一些值
@Autowired
public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
this.objectPostProcessor = objectPostProcessor;
// 这个 authenticationBuilder 被设置进了 httpSecurity 里面
authenticationBuilder = new AuthenticationManagerBuilder(objectPostProcessor);
localConfigureAuthenticationBldr = new AuthenticationManagerBuilder(objectPostProcessor) {
@Override
public AuthenticationManagerBuilder eraseCredentials(boolean eraseCredentials) {
authenticationBuilder.eraseCredentials(eraseCredentials);
return super.eraseCredentials(eraseCredentials);
}
};
}
// 往 map 里面丢了一堆值, 以后要用就在里面取
// Creates the shared objects
private Map<Class<? extends Object>, Object> createSharedObjects() {
Map<Class<? extends Object>, Object> sharedObjects = new HashMap<Class<? extends Object>, Object>();
sharedObjects.putAll(localConfigureAuthenticationBldr.getSharedObjects());
sharedObjects.put(UserDetailsService.class, userDetailsService());
sharedObjects.put(ApplicationContext.class, context);
sharedObjects.put(ContentNegotiationStrategy.class, contentNegotiationStrategy);
sharedObjects.put(AuthenticationTrustResolver.class, trustResolver);
return sharedObjects;
}
}
小结
- authenticationBuilder.parentAuthenticationManager(authenticationManager());
- authenticationManager() 方法获取 AuthenticationManager 是根据用户的使用情况
- 是否重载了 configure(AuthenticationManagerBuilder auth) 方法,
- 没有重载就是在 AuthenticationConfiguration#getAuthenticationManager() 方法里被创建, 这样会注入一些默认的 bean.
- 重载了, 那就是在 WebSecurityConfigurer 里创建一个空的实例, 然后执行 build().
- 创建了一个 AuthenticationManager , 然后设置进 authenticationBuilder 的父管理里面了
- 之后又把 authenticationBuilder 设置进了 httpSecurity 对象里面;
0x02 看一下 AuthenticationConfiguration 里面做了些什么
AuthenticationConfiguration 这个类的详细解析
@Configuration
@Import(ObjectPostProcessorConfiguration.class)
public class AuthenticationConfiguration {
@Bean
public AuthenticationManagerBuilder authenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
return new AuthenticationManagerBuilder(objectPostProcessor);
}
// 此方法就是上面调用的用于获取 AuthenticationManager 实例的方法
public AuthenticationManager getAuthenticationManager() throws Exception {
// 用原子布尔值, 同步
if (this.authenticationManagerInitialized) {
return this.authenticationManager;
}
// new 了一个实例
AuthenticationManagerBuilder authBuilder = authenticationManagerBuilder(this.objectPostProcessor);
if (this.buildingAuthenticationManager.getAndSet(true)) {
return new AuthenticationManagerDelegator(authBuilder);
}
// 全局的鉴权配置
// globalAuthConfigurers 是被 spring 控制注入的 List<GlobalAuthenticationConfigurerAdapter> 类型
for (GlobalAuthenticationConfigurerAdapter config : globalAuthConfigurers) {
authBuilder.apply(config);
}
// 创建 authenticationManager
authenticationManager = authBuilder.build();
// 如果获取不到, 就尝试懒加载实例
if (authenticationManager == null) {
authenticationManager = getAuthenticationManagerBean();
}
this.authenticationManagerInitialized = true;
return authenticationManager;
}
private AuthenticationManager getAuthenticationManagerBean() {
// 返回一个懒加载的代理对象
return lazyBean(AuthenticationManager.class);
}
}
- 直接创建了 AuthenticationManagerBuilder, 导入了一些默认的 GlobalAuthenticationConfigurerAdapter 配置, 然后执行 build();
- 而如果重载了 configure(AuthenticationManagerBuilder auth) 方法, 则是直接 new 的一个对象, 没有设置值, 直接 build();
- 将这个值设置进了 AuthenticationManagerBuilder 的父管理里面了
0x03 AuthenticationManagerBuilder#build() 做了些什么
AuthenticationManagerBuilder 继承了 AbstractSecurityBuilder<O>, 也是一个构造器.
通过前面 webSecurity 的学习, 我们知道了, builder 的执行逻辑.
先将抽象类里面的 configurers 执行 init(), configurer() 方法, 然后执行 perfromBuild();
只是不同的是, 目前, 也就是以上的 builder 里面 configurers 设置的值要么是默认的, 要么是没有的;
当然我们目前获取的这个 authenticationManager, 被设置进了 builder 的 parentAuthenticationManager;
AuthenticationManager authenticationManager = authenticationManager();
authenticationBuilder.parentAuthenticationManager(authenticationManager);
然后这个 authenticationBuilder 被 httpSecurity 放在了共享变量里面;
后期在 configurer 里面会给它加入一些 provider
0x04 httpSecurity 的配置过程
以下是默认的 http 配置, 我们分析一下其中几个
http
.csrf().and()
.addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling().and()
.headers().and()
.sessionManagement().and()
.securityContext().and()
.requestCache().and()
.servletApi().and()
.apply(new DefaultLoginPageConfigurer<HttpSecurity>()).and()
.logout();
- .anonymous().and()
- .addFilter(new WebAsyncManagerIntegrationFilter())
public final class HttpSecurity extends
AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity> {
// 当执行 http.anonymous() 的时候, 就是向 httpSecurity 里面的 configurers 里面添加了一个配置对象
// getOrApply() 方法就是, 如果有这个配置就返回实例
// 如果没有, 就创建并添加这个配置到集合里, 然后放回实例
public AnonymousConfigurer<HttpSecurity> anonymous() throws Exception {
return getOrApply(new AnonymousConfigurer<HttpSecurity>());
}
// 其他方法也是大同小异,
// 这个配置不就是全局的异常处理器嘛.
public ExceptionHandlingConfigurer<HttpSecurity> exceptionHandling() throws Exception {
return getOrApply(new ExceptionHandlingConfigurer<HttpSecurity>());
}
// 应用一个 filter 过滤器, 这样应用必须要在 spring security 里面的 FilterComparator 有记录
public HttpSecurity addFilter(Filter filter) {
Class<? extends Filter> filterClass = filter.getClass();
// 如果 filter 没有设置排序值
if (!comparator.isRegistered(filterClass)) {
throw new IllegalArgumentException(""); // 错误信息省略
}
this.filters.add(filter);
return this;
}
// 不然的话, 只能使用 addFilterBefore(), 先将自定义的 filter 记录在 FilterComparator 里, 然后添加
public HttpSecurity addFilterBefore(Filter filter, Class<? extends Filter> beforeFilter) {
comparator.registerBefore(filter.getClass(), beforeFilter);
return addFilter(filter);
}
}
至于 apply(configurer) 这就是在 AbstractConfiguredSecurityBuilder 里面定义的, 向 configuruers 添加配置的方法;
0x05 httpSecurity 的 configurer 配置, 都做了什么事情
我们把 AnonymousConfigurer
这个配置当例子讲一下
public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractHttpConfigurer<AnonymousConfigurer<H>, H> {
// 省略了一些方法, 他们的主要作用就是用来设置 (定制) 一些匿名登录用户的信息
// 同时也配置了 AnonymousAuthenticationProvider 和 AnonymousAuthenticationFilter
// 主要看着两个方法, 如果没有用户定制 authenticationProvider authenticationFilter 两个变量的实现类
// 那就使用自己 new 的类
@Override
public void init(H http) throws Exception {
if (authenticationProvider == null) {
authenticationProvider = new AnonymousAuthenticationProvider(getKey());
}
if (authenticationFilter == null) {
authenticationFilter = new AnonymousAuthenticationFilter(getKey(), principal, authorities);
}
// 这里后置加工, 和我们之前讲的差不多, 都是为了能让 spring ioc 容器管理自己 new 的 bean
authenticationProvider = postProcess(authenticationProvider);
// 注意这里!! 这里就是向 authenticationManager 里面添加了配置信息
http.authenticationProvider(authenticationProvider);
}
// 这里向 httpSecurity 里面添加了 AnonymousAuthenticationFilter
@Override
public void configure(H http) throws Exception {
authenticationFilter.afterPropertiesSet();
http.addFilter(authenticationFilter);
}
}
-
这个配置类的 init(), 和 configurer() 方法什么时候被调用呢;
- 当 webSecurity 执行 build() 的时候, 执行了 httpSecurity 的 build() 方法
- http.build() 执行的时候, 分别对设置的所有配置类执行他们自己的 init(), configueer(),
- init() 只是初始化, 这里设置了 authenticationManager 的配置信息
- configueer() 设置了 httpSecurity 构造的对象的信息.
- 这步执行完成之后, httpSecurity 构造的对象的信息就全都设置好, 并且装载好了
- perfromBuile() 只是根据这些配置信息实例化最终需要的对象就好了.
- 然后执行 perfromBuile() 构造出所需对象;
-
httpSecurity 里面向 authenticationManager 添加配置的方法
public final class HttpSecurity extends
AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity> {
public HttpSecurity(ObjectPostProcessor<Object> objectPostProcessor,
AuthenticationManagerBuilder authenticationBuilder,
Map<Class<? extends Object>, Object> sharedObjects) {
super(objectPostProcessor);
Assert.notNull(authenticationBuilder, "authenticationBuilder cannot be null");
// 在这里将 authenticationBuilder 设置进了共享 map 里面
setSharedObject(AuthenticationManagerBuilder.class, authenticationBuilder);
for (Map.Entry<Class<? extends Object>, Object> entry : sharedObjects.entrySet()) {
setSharedObject((Class<Object>) entry.getKey(), entry.getValue());
}
ApplicationContext context = (ApplicationContext) sharedObjects.get(ApplicationContext.class);
this.requestMatcherConfigurer = new RequestMatcherConfigurer(context);
}
// 从共享对象里面拿了一个 AuthenticationManagerBuilder 的值, 并把它返回
// 这个值就是我们最开始被设置了父权限工厂的那个对象,
// 当时执行构造方法, http = new HttpSecurity(objectPostProcessor, authenticationBuilder, sharedObjects);
// 将那个 buauthenticationBuilder 放在了共享的 map 里面
public HttpSecurity authenticationProvider(AuthenticationProvider authenticationProvider) {
getAuthenticationRegistry().authenticationProvider(authenticationProvider);
return this;
}
private AuthenticationManagerBuilder getAuthenticationRegistry() {
return getSharedObject(AuthenticationManagerBuilder.class);
}
public <C> C getSharedObject(Class<C> sharedType) {
return (C) this.sharedObjects.get(sharedType);
}
// 注意这个方法, 等下将
@Override
protected void beforeConfigure() throws Exception {
setSharedObject(AuthenticationManager.class, getAuthenticationRegistry().build());
}
}
而 getAuthenticationRegistry().authenticationProvider(authenticationProvider);
的 authenticationProvider()
方法在 AuthenticationManagerBuilder
里面, 此方法也只是向 authenticationProviders
里面添加了一个权限管理的 configure.
public class AuthenticationManagerBuilder
extends AbstractConfiguredSecurityBuilder<AuthenticationManager, AuthenticationManagerBuilder>
implements ProviderManagerBuilder<AuthenticationManagerBuilder> {
public AuthenticationManagerBuilder authenticationProvider(AuthenticationProvider authenticationProvider) {
this.authenticationProviders.add(authenticationProvider);
return this;
}
// ProviderManager 实现了 AuthenticationManager 接口
// 它使用 authenticationProviders, parentAuthenticationManager 初始化了一个 ProviderManager()
// parentAuthenticationManager 就是我们一直说的 父权限管理
@Override
protected ProviderManager performBuild() throws Exception {
if (!isConfigured()) {
logger.debug("No authenticationProviders and no parentAuthenticationManager defined. Returning null.");
return null;
}
ProviderManager providerManager = new ProviderManager(authenticationProviders, parentAuthenticationManager);
if (eraseCredentials != null) {
providerManager.setEraseCredentialsAfterAuthentication(eraseCredentials);
}
if (eventPublisher != null) {
providerManager.setAuthenticationEventPublisher(eventPublisher);
}
providerManager = postProcess(providerManager);
return providerManager;
}
}
现在思路已经很明确了, 还记得上篇随便提了一下的 beforeConfigurer() 这个方法吗.
上面 AuthenticationManagerBuilder.build() 方法的调用就发生在 httpSecurity 的这个方法里面
所以这样就构造了一个 AuthenticationManager 对象.
@Override
protected void beforeConfigure() throws Exception {
setSharedObject(AuthenticationManager.class, getAuthenticationRegistry().build());
}
0x06 从头梳理一下整个的流程 (将上一章结尾的流程细化)
细化的 (新加的) 流程我用 - [num] 标记
- 从 WebSecurityConfiguration 类的 setFilterChainProxySecurityConfigurer() 方法说起;
- 在参数上的 sqel 表达式, 收集到应用环境里面所有的 WebSecurityConfigurer,
- 将他设置进 SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurers 参数里面
- new 一个 webSecurity 对象, 并用 objectPostProcessor 处理, 让他具有和被 ioc 持有的 bean 一样的性质
- 将 webSecurityConfigurers 进行排序, 如果排序值相同就报错
- 依次将 webSecurityConfigurers 里面的每一个 WebSecurityConfigurer 设置进 WebSecurity 里面;
- 将 WebSecurityConfigurer 设置进 WebSecurity 调用了它的 apply() 方法
- 也就是将 WebSecurityConfigurer 设置到 AbstractConfiguredSecurityBuilder 的 configurers 里面
- configurers 的类型是 LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>>
- 最后将 WebSecurityConfiguration 类的 webSecurityConfigurers 属性赋值
- springSecurityFilterChain() 返回一个'springSecurityFilterChain'
- 查看 WebSecurityConfiguration 类的 webSecurityConfigurers 是否有值
- 没有的话, 就向 WebSecurity 里 apply() 一个默认的 WebSecurityConfigurer
- 执行 webSecurity 的 build() 方法
- 执行 doBuild() 保证对象是单例的
- 执行 init() 方法
- 执行 configurers 里每一个 configurer 的 init(B builder) 方法
- configurer#init(B builder) 方法传入的就是在上面创建的 WebSecurity 对象
- WebSecurityConfigurerAdapter#init(WebSecurity web) 将会用 getHttp() 初始化一个 httpSecurity 对象
- [0] getHttp() 返回了一个 httpSecurity 实例
- [1] 获取一个 authenticationManager 并设置进 authenticationBuilder 的父权限管理里面
// 这里也是建造者模式, 流程相识, 不详细介绍
- [1.1] 如果 configure(authenticationManagerBuilder auth) 被重写覆盖了
- authenticationManager 是从 AuthenticationConfiguration#getAuthenticationManager() 方法获取的对象;
- [1.2] 如果没有, 则是一个没有配置属性, 直接 build() 返回的 authenticationManager
- [2] 创建了共享变量 sharedObjects
- [3] httpSecurity = new HttpSecurity(objectPostProcessor, authenticationBuilder, sharedObjects);
- [4] 使用. anonymous().and() 等方式, 向 httpSecurity 实例里添加配置
- [5] 根据 java spi 规则, 向 httpSecurity 实例里添加配置
- [6] 执行被我们继承重写的 configure(HttpSecurity http) 方法
- 并把 httpSecurity 对象 设置进 web(也就是前面创建的 webSecurity) 的 securityFilterChainBuilders 属性里面
- 获取 httpSecurity 里 FilterSecurityInterceptor 类型的共享对象, 设置进 webSecurity 里面
- 执行 configure() 方法
- 执行 configurers 里每一个 configurer 的 configure(B builder) 方法
- WebSecurityConfigurerAdapter#configure(WebSecurity web) 默认空方法, 一般用于设置需要忽略的请求
- 也就是往 ignoredRequests 里面加 RequestMatcher
- 执行 performBuild() 方法
- 创建一个 securityFilterChains, 类型是 List<SecurityFilterChain>
- 遍历 webSecurity 的 ignoredRequests, 创建匹配不处理路径的 SecurityFilterChain, 将他加入 securityFilterChains
- 遍历 securityFilterChainBuilders(也就是所有 httpSecurity 对象), 执行 httpSecurit 的 build(), 将返回的值加入 securityFilterChains
- httpSecurity#build(), 这个方法返回一个过滤器链 DefaultSecurityFilterChain(requestMatcher, filters)
- requestMatcher 是 uri 的匹配规则, 默认的 AnyRequestMatcher.INSTANCE;
- filters 是一组利用 http.and() 加入的过滤器 List<Filter> filters = new ArrayList<Filter>();
- [0] build() 方法依次执行 init(), beforeConfigure(), performBuild()
- [1] init() 方法, 将 httpSecurity 里面的配置初始化, 为 configure() 做准备;
- [1.1] 我们知道 security 流程里, filter 和 provider 配合使用的,
- [1.2] 这一步就是把这个 filter 对应的 provider 加入了 authenticationManagerBuilder 里, 不是加了一个 provider 配置
- [2] beforeConfigure() 这步调用 authenticationManagerBuilder 的 build() 创建了一个 authenticationManager 并加入共享变量里
// 这步完成后, 我们就可以用这个方法来授权了 this.getAuthenticationManager().authenticate(customToken);
- [3] performBuild() 返回了 SecurityFilterChain
- 用 securityFilterChains 创建一个 FilterChainProxy 对象
- 设置 filterChainProxy 的一些属性, 转型为 Filter, 并将它返回 (这也就是我们的目标'springSecurityFilterChain' )
还有一些常用对象比如 UserDetailsService, BCryptPasswordEncoder 等, 也大同小异, 在哪里创建了配置然后 apply 进去, 主要流程是这样的
对于一个请求来了的具体过滤执行流程很简单, 但是不想写了
然后 OAuth2 之类的, 不太熟练, 就放弃啦~;
0x07 balabalabala…
AuthenticationManageRBuilder 的初始化和配置过程, 并不是很清晰.
而且大佬设计框架的时候, 提前留空了 beforeConfigure() 感觉很神奇;
AbstractConfiguredSecurityBuilder 类和 SecurityConfigurer<O, B> 这个接口组合在一起, 是真的代码复用到爆炸
只能说, 给大佬跪了, orz, 作为菜鸡的我还有好长的路要走;
学习一个
// abcdefghijklmnopqrstovwxyz