当前位置: 首页 > article >正文

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> {
     
    //声明一个 provider
	private DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
    //声明一个 UserDetailsService
	private 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;
	}

	@Override
	public void configure(B builder) throws Exception {
        //调用后置处理器 将provider添加到SpringIoC容器中
		this.provider = postProcess(this.provider);
        // 将provider添加到builder对象中
		builder.authenticationProvider(this.provider);
	}

	/**
	 * 
	 */
	@Override
	public 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 GlobalAuthenticationConfigurerAdapter
		implements SecurityConfigurer<AuthenticationManager, AuthenticationManagerBuilder> {

	@Override
	public void init(AuthenticationManagerBuilder auth) throws Exception {
	}

	@Override
	public void configure(AuthenticationManagerBuilder auth) throws Exception {
	}

}

    

4、WebSecurityConfigurer

      WebSecurityConfigurer 只有一个实现,即 WebSecurityConfigurerAdapter;当我们自定义

      SpringSecurity 配置时,需要继承类 WebSecurityConfigurerAdapter;

      所以这里 WebSecurityConfigurer 功能就很明确了,即用户扩展用户自定义的配置。

             

        WebSecurityConfigurer 使用示例:

               


http://www.kler.cn/news/308283.html

相关文章:

  • 拖拽排序的实现示例demo
  • Mysql调优之性能监控(一)
  • C++11(5)
  • 5G毫米波阵列天线仿真——CDF计算(手动AC远场)
  • 服务器究竟该怎么防范UDP泛洪攻击?
  • 【计算机网络】TCP 协议——详解三次握手与四次挥手
  • 中秋节程序员一般在干啥?
  • 管道焊缝质量数据集——good和bad两种标签,0为good.1134个图片,有对应的xml标签和txt标签,可用于yolo训练
  • LLMs之SuperPrompt:SuperPrompt的简介、使用方法、案例应用之详细攻略
  • 初赛笔记2
  • linux使用命令行编译qt.cpp
  • 【LeetCode每日一题】——LCR 078.合并 K 个升序链表
  • SpringSecurity原理解析(八):CSRF防御解析
  • Java集合框架 迭代器
  • 麒麟操作系统搭建Nacos集群
  • 面试经典150题——最后一个单词的长度
  • 基于双向RRT算法的三维空间最优路线规划matlab仿真
  • 云服务器开放端口
  • 短信验证码倒计时 (直接复制即可使用) vue3
  • 今日leetCode 242.有效的字母异位词
  • 【二叉树进阶】二叉搜索树
  • 视频格式转为mp4(使用ffmpeg)
  • 小程序面试题八
  • 【百日算法计划】:每日一题,见证成长(014)
  • 【SQL Server】清除日志文件ERRORLOG、tempdb.mdf
  • 如何快准稳 实现MySQL大表历史数据迁移?
  • linux文件系统权限详解
  • 服务器——装新的CUDA版本的方法
  • Web:HTTP包的相关操作
  • RocksDB系列一:基本概念