SpringSecurity原理解析(六):SecurityConfigurer 解析
1、SecurityConfigurer
SecurityConfigurer 在 Spring Security 中是一个非常重要的接口,观察HttpSecurity 中的很多
方法可以发现,SpringSecurity 中的每一个过滤器都是通过 xxxConfigurer 来进行配置的,而
这些 xxxConfigurer 其实都是 SecurityConfigurer 的实现。
SecurityConfigurer 是一个接口,其定义如下:
public interface SecurityConfigurer<O, B extends SecurityBuilder<O>> {/*** Initialize the {@link SecurityBuilder}. Here only shared state should be created* and modified, but not properties on the {@link SecurityBuilder} used for building* the object. This ensures that the {@link #configure(SecurityBuilder)} method uses* the correct shared objects when building. Configurers should be applied here.* @param builder* @throws Exception** 初始化 SecurityBuilder*/void init(B builder) throws Exception;/*** Configure the {@link SecurityBuilder} by setting the necessary properties on the* {@link SecurityBuilder}.* @param builder* @throws Exception** 通过设置必要的属性来配置 SecurityBuilder*/void configure(B builder) throws Exception;}
由 SecurityConfigurer 定义可以发现 init方法和 configure方法的参数都是 SecurityBuilder 的类
型,而SecurityBuilder是用来构建过滤器链 DefaultSecurityFilterChainProxy的,从前边
的笔记可以知道 DefaultSecurityFilterChainProxy 是 SecurityConfigurer 的是实现类
AbstractConfiguredSecurityBuilder中构建的。
SecurityConfigurer 的实现有很多,但我们只需要关注其中三个核心实现,即:
SecurityConfigurerAdapter
GlobalAuthenticationConfigurerAdapter
WebSecurityConfigurer
2、SecurityConfigurerAdapter
SecurityConfigurerAdapter 是 SecurityConfigurer 的基础实现类(抽象类),并没有实现
接口 SecurityConfigurer 的方法,而是在SecurityConfigurer 的基础上扩展了几个方法;
在SpringSecurity 中很多xxxConfigurer也是 SecurityConfigurerAdapter 的子类。
2.1、SecurityConfigurerAdapter 核心属性
SecurityConfigurerAdapter 核心属性只有2个,一个是 SecurityBuilder 类型 另一个是
CompositeObjectPostProcessor,如下图所示:
其中 CompositeObjectPostProcessor 是 SecurityConfigurerAdapter 的一个内部类,并实现
了接口 ObjectPostProcessor,ObjectPostProcessor 是一个后置处理器,
ObjectPostProcessor只有2个实现,即 AutowireBeanFactoryObjectPostProcessor 和
CompositeObjectPostProcessor;
1)AutowireBeanFactoryObjectPostProcessor :
该类主要功能是通过 AutowireCapableBeanFactory 将指定的bean对象注册到spring容器
中,通过前边HttpSecurity 中的方法可以窥见一斑,SpringSecurity 中的对象很多都是直
接new 出来的,这些new手动创建的对象需要手动注册到spring容器中后,在其他地方才
能访问;AutowireBeanFactoryObjectPostProcessor 就是用来将这些new 出来的对象注
册到spring容器的。如下图所示:
2)CompositeObjectPostProcessor
CompositeObjectPostProcessor 则是一个复合的对象处理器,里边维护了一个 List 集
合,这个List 集合中,大部分情况下只存储一条数据,那就是
AutowireBeanFactoryObjectPostProcessor(因为 ObjectPostProcessor 就2个实现,除
了CompositeObjectPostProcessor 自身,剩下的只有
AutowireBeanFactoryObjectPostProcessor ),用来完成对象注入到容器的操作;
2.2、SecurityConfigurerAdapter 常用方法
2.2.1、addObjectPostProcessor
若用户手动调用了该方法,那么CompositeObjectPostProcessor 集合中维护的数据就会增
加一条,CompositeObjectPostProcessor.postProcess 方法中,会遍历集合中的所有
ObjectPostProcessor,挨个调用其 postProcess 方法对对象进行后置处理。
public void addObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {this.objectPostProcessor.addObjectPostProcessor(objectPostProcessor);}
2.2.2、add()
该方法返回值是一个 securityBuilder,这里securityBuilder 实际上就是 HttpSecurity,我们
在HttpSecurity 中去配置不同的过滤器时,可以使用 and 方法进行链式配置,就是因为这
里定义了 and 方法并返回了 securityBuilder 实例
public B and() {return getBuilder();}protected final B getBuilder() {Assert.state(this.securityBuilder != null, "securityBuilder cannot be null");return this.securityBuilder;}
2.3、SecurityConfigurerAdapter 核心子类
SecurityConfigurerAdapter 的主要子类也是有个,即:
1)UserDetailsAwareConfigurer
2) AbstractHttpConfigurer
3)LdapAuthenticationProviderConfigurer
由于 LDAP 现在使用很少,所以这里重点介绍下前两个
2.3.1、UserDetailsAwareConfigurer
UserDetailsAwareConfigurer是用户配置相关的类,定义如下:
public abstract class UserDetailsAwareConfigurer<B extends ProviderManagerBuilder<B>, U extends UserDetailsService>extends SecurityConfigurerAdapter<AuthenticationManager, B> {/*** 返回的是UserDetailsService 接口的实现* Gets the {@link UserDetailsService} or null if it is not available* @return the {@link UserDetailsService} or null if it is not available*/public abstract U getUserDetailsService();}
通过定义我们可以看到泛型U必须是UserDetailsService接口的实现,也就是
getUserDetailsService()方法返回的肯定是UserDetailsService接口的实现,还有通
过泛型B及继承SecurityConfigurerAdapter来看,UserDetailsAwareConfigurer类中应该
会构建一个AuthenticationManager对象。
2.3.1.1、AbstractDaoAuthenticationConfigurer
UserDetailsAwareConfigurer 只有一个子类,即 AbstractDaoAuthenticationConfigurer;
AbstractDaoAuthenticationConfigurer 类的主要用于配置DaoAuthenticationProvider;
AbstractDaoAuthenticationConfigurer 类定义如下:
// B--ProviderManagerBuilder
// C--AbstractDaoAuthenticationConfigurer
// U--UserDetailsService
public abstract class AbstractDaoAuthenticationConfigurer<B extends ProviderManagerBuilder<B>, C extends AbstractDaoAuthenticationConfigurer<B, C, U>, U extends UserDetailsService>extends UserDetailsAwareConfigurer<B, U> {//声明一个 providerprivate DaoAuthenticationProvider provider = new DaoAuthenticationProvider();//声明一个 UserDetailsServiceprivate final U userDetailsService;/*** 传递的对象可以是UserDetailsService或者UserDetailsPasswordService*/AbstractDaoAuthenticationConfigurer(U userDetailsService) {this.userDetailsService = userDetailsService;this.provider.setUserDetailsService(userDetailsService);if (userDetailsService instanceof UserDetailsPasswordService) {this.provider.setUserDetailsPasswordService((UserDetailsPasswordService) userDetailsService);}}/*** 添加了一个ObjectPostProcessor 后置处理器*/@SuppressWarnings("unchecked")public C withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {addObjectPostProcessor(objectPostProcessor);return (C) this;}/*** 添加密码编码器 用于加密*/@SuppressWarnings("unchecked")public C passwordEncoder(PasswordEncoder passwordEncoder) {this.provider.setPasswordEncoder(passwordEncoder);return (C) this;}public C userDetailsPasswordManager(UserDetailsPasswordService passwordManager) {this.provider.setUserDetailsPasswordService(passwordManager);return (C) this;}@Overridepublic void configure(B builder) throws Exception {//调用后置处理器 将provider添加到SpringIoC容器中this.provider = postProcess(this.provider);// 将provider添加到builder对象中builder.authenticationProvider(this.provider);}/*** */@Overridepublic U getUserDetailsService() {return this.userDetailsService;}}
AbstractDaoAuthenticationConfigurer 也只有一个子类,即UserDetailsServiceConfigurer
UserDetailsServiceConfigurer
该类的功能是用于在AuthenticationManagerBuilder中配置UserDetailsService。
该类实现的核心是在 configure 方法执行之前加入了 initUserDetailsService 方
法,以方便开发展按照自己的方式去初始化 UserDetailsService;
在 UserDetailsServiceConfigurer 中 initUserDetailsService 是抽象方法,由子类
去实现,如下图所示:
UserDetailsManagerConfigurer类:
UserDetailsManagerConfigurer是 UserDetailsServiceConfigurer 的子类,
UserDetailsManagerConfigurer 中实现了 UserDetailsServiceConfigurer 中定义的
initUserDetailsService 方法,具体的实现逻辑就是将 UserDetailsBuilder 所构建出
来的 UserDetails 以及提前准备好的 UserDetails 中的用户存储到 UserDetailsService
中。
该类同时添加了 withUser 方法用来添加用户,同时还增加了一个 UserDetailsBuilder
用来构建用 户。
UserDetailsManagerConfigurer 有2个子类,分别是:
JdbcUserDetailsManagerConfigurer
InMemoryUserDetailsManagerConfigurer
JdbcUserDetailsManagerConfigurer类:
JdbcUserDetailsManagerConfigurer 在父类的基础上补充了 DataSource 对象,
同时还提供了相应 的数据库查询方法
InMemoryUserDetailsManagerConfigurer类:
InMemoryUserDetailsManagerConfigurer 在父类的基础上重写了构造方法,
将父类中的 UserDetailsService 实例定义为 InMemoryUserDetailsManager,
如下所示:
public class InMemoryUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>>extends UserDetailsManagerConfigurer<B, InMemoryUserDetailsManagerConfigurer<B>> {/*** Creates a new instance*/public InMemoryUserDetailsManagerConfigurer() {super(new InMemoryUserDetailsManager(new ArrayList<>()));}}
2.3.2、AbstractHttpConfigurer
AbstractHttpConfigurer是 在HttpSecurity上运行的SecurityConfigurer实例 的基类;也
就是说 HttpSecurity 上运行的 SecurityConfigurer 都是 AbstractHttpConfigurer 的子类。
AbstractHttpConfigurer 子类有很多,SpringSecurity 中的过滤器配置类都继承
了 AbstractHttpConfigurer,如: FormLoginConfigurer、DefaultLoginPageConfigurer
和 CsrfConfigurer 等等。
AbstractHttpConfigurer 继承于SecurityConfigurerAdapter,并扩展了2个方法,
AbstractHttpConfigurer 定义如下:
public abstract class AbstractHttpConfigurer<T extends AbstractHttpConfigurer<T, B>, B extends HttpSecurityBuilder<B>>extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, B> {/*** getBuilder 中移除相关的 xxxConfigurer,* getBuilder 方法获取到的实际上就是 HttpSecurity,所以移除掉 xxxConfigurer 实际上就是从过滤器链中移除掉某一个过滤器*/@SuppressWarnings("unchecked")public B disable() {getBuilder().removeConfigurer(getClass());return getBuilder();}/***为配置类添加手动添加后置处理器,返回值是当前配置类,** 该方法常用于链式配置上**/@SuppressWarnings("unchecked")public T withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {addObjectPostProcessor(objectPostProcessor);return (T) this;}}
3、GlobalAuthenticationConfigurerAdapter
GlobalAuthenticationConfigurerAdapter 是一个全局的配置类,使用该类对应的Bean 对象可以
用来配置全局的 AuthenticationManagerBuilder;
GlobalAuthenticationConfigurerAdapter 实现了 SecurityConfigurerAdapter 接口,但是并未对
方法做具体的实现,只是将泛型具体化了
GlobalAuthenticationConfigurerAdapter 定义如下:
@Order(100)
public abstract class GlobalAuthenticationConfigurerAdapterimplements SecurityConfigurer<AuthenticationManager, AuthenticationManagerBuilder> {@Overridepublic void init(AuthenticationManagerBuilder auth) throws Exception {}@Overridepublic void configure(AuthenticationManagerBuilder auth) throws Exception {}}
4、WebSecurityConfigurer
WebSecurityConfigurer 只有一个实现,即 WebSecurityConfigurerAdapter;当我们自定义
SpringSecurity 配置时,需要继承类 WebSecurityConfigurerAdapter;
所以这里 WebSecurityConfigurer 功能就很明确了,即用户扩展用户自定义的配置。
WebSecurityConfigurer 使用示例: