spring security加载流程

文档

  1. 00 - spring security框架使用
  2. 01 - spring security自定义登录页面
  3. 02 - spring security基于配置文件及内存的账号密码
  4. 03 - spring security自定义登出页面
  5. 04 - spring security关闭csrf攻击防御
  6. 05 - spring security权限控制
  7. 06 - spring security角色和权限设置
  8. 07 - spring security基于数据库的账号密码
  9. 08 - spring security基于jdbc的账号密码

说明

  1. spring security版本:3.2.0

spring security加载流程

  1. 创建HttpSecurity对象,此处用的是@Scope("prototype")注解,在自定义配置中,操作的就是该对象

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by FernFlower decompiler)
    //
    
    package org.springframework.security.config.annotation.web.configuration;
    
    @Configuration(
        proxyBeanMethods = false
    )
    class HttpSecurityConfiguration {
        
        // ...
        
        @Bean({"org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.httpSecurity"})
        @Scope("prototype")
        HttpSecurity httpSecurity() throws Exception {
            LazyPasswordEncoder passwordEncoder = new LazyPasswordEncoder(this.context);
            AuthenticationManagerBuilder authenticationBuilder = new DefaultPasswordEncoderAuthenticationManagerBuilder(this.objectPostProcessor, passwordEncoder);
            authenticationBuilder.parentAuthenticationManager(this.authenticationManager());
            authenticationBuilder.authenticationEventPublisher(this.getAuthenticationEventPublisher());
            HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, this.createSharedObjects());
            WebAsyncManagerIntegrationFilter webAsyncManagerIntegrationFilter = new WebAsyncManagerIntegrationFilter();
            webAsyncManagerIntegrationFilter.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
            http.csrf(Customizer.withDefaults()).addFilter(webAsyncManagerIntegrationFilter).exceptionHandling(Customizer.withDefaults()).headers(Customizer.withDefaults()).sessionManagement(Customizer.withDefaults()).securityContext(Customizer.withDefaults()).requestCache(Customizer.withDefaults()).anonymous(Customizer.withDefaults()).servletApi(Customizer.withDefaults()).apply(new DefaultLoginPageConfigurer());
            http.logout(Customizer.withDefaults());
            this.applyCorsIfAvailable(http);
            this.applyDefaultConfigurers(http);
            return http;
        }
        
    }
    
  2. 默认的SecurityFilterChain对象

    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnWebApplication(
        type = Type.SERVLET
    )
    class SpringBootWebSecurityConfiguration {
        
        // ...
    
        @Configuration(
            proxyBeanMethods = false
        )
        @ConditionalOnDefaultWebSecurity
        static class SecurityFilterChainConfiguration {
            SecurityFilterChainConfiguration() {
            }
    
            @Bean
            @Order(2147483642)
            SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
                http.authorizeHttpRequests((requests) -> {
                    ((AuthorizeHttpRequestsConfigurer.AuthorizedUrl)requests.anyRequest()).authenticated();
                });
                http.formLogin(Customizer.withDefaults());
                http.httpBasic(Customizer.withDefaults());
                return (SecurityFilterChain)http.build();
            }
        }
    }
    
  3. 上面是默认的SecurityFilterChain类型的Bean,实际使用中,我们会自定义SecurityFilterChain类型的Bean,当我们自定义时,上面的默认配置会失效

  4. 定义SecurityFilterChain类型的Bean时,会注入HttpSecurity对象,就是在最开始的流程中创建的,在调用HttpSecurity以下方法时,会创建更多其它相关的对象

    1. http.formLogin(Customizer.withDefaults());,1️⃣
    2. http.build(),6️⃣
  5. 接口:SecurityBuilder

    1. 实现类:AbstractSecurityBuilder

      1. 方法:public final O build() throws Exception,7️⃣

        public final O build() throws Exception {
            if (this.building.compareAndSet(false, true)) {
             this.object = this.doBuild();
                return this.object;
         } else {
                throw new AlreadyBuiltException("This object has already been built");
         }
        }
        
      2. 子类:AbstractConfiguredSecurityBuilder

        1. 属性:private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers;

        2. 方法:protected final O doBuild() throws Exception,8️⃣

          protected final O doBuild() throws Exception {
              synchronized(this.configurers) {
                  this.buildState = AbstractConfiguredSecurityBuilder.BuildState.INITIALIZING;
                  this.beforeInit();
                  this.init();
                  this.buildState = AbstractConfiguredSecurityBuilder.BuildState.CONFIGURING;
                  this.beforeConfigure();
                  this.configure();
                  this.buildState = AbstractConfiguredSecurityBuilder.BuildState.BUILDING;
                  O result = this.performBuild();
                  this.buildState = AbstractConfiguredSecurityBuilder.BuildState.BUILT;
                  return result;
              }
          }
          

          说明:

          1. 关注this.beforeConfigure();this.configure();方法
        3. 方法:private void configure(),🔟

          private void configure() throws Exception {
              Collection<SecurityConfigurer<O, B>> configurers = this.getConfigurers();
              Iterator var2 = configurers.iterator();
          
              while(var2.hasNext()) {
                  SecurityConfigurer<O, B> configurer = (SecurityConfigurer)var2.next();
                  configurer.configure(this);
              }
          
          }
          

          说明:这里我们关注FormLoginConfigurer

        4. 子类:HttpSecurity

          1. 方法:public HttpSecurity formLogin(Customizer<FormLoginConfigurer<HttpSecurity>> formLoginCustomizer) throws Exception,2️⃣

            public HttpSecurity formLogin(Customizer<FormLoginConfigurer<HttpSecurity>> formLoginCustomizer) throws Exception {
                formLoginCustomizer.customize((FormLoginConfigurer)this.getOrApply(new FormLoginConfigurer()));
                return this;
            }
            

            说明:

            1. 实际使用中,我们会在自定义SecurityFilterChain类型的Bean时,注入HttpSecurity对象,并且调用formLogin方法
            2. formLogin方法的入参formLoginCustomizer,一般会以匿名内部类的方式传入,该匿名内部类重写customize方法
            3. customize方法的入参为FormLoginConfigurer对象,所以在我们自定义的配置中,实际操作的是FormLoginConfigurer对象,该对象来自于(FormLoginConfigurer)this.getOrApply(new FormLoginConfigurer())
            4. (FormLoginConfigurer)this.getOrApply(new FormLoginConfigurer())会向configurers属性中添加一个键值对this.configurers.put(clazz, configs);configsList类型,new FormLoginConfigurer()是其中的元素
          2. 方法:protected void beforeConfigure() throws Exception,9️⃣

            protected void beforeConfigure() throws Exception {
                if (this.authenticationManager != null) {
                    this.setSharedObject(AuthenticationManager.class, this.authenticationManager);
                } else {
                    ObservationRegistry registry = this.getObservationRegistry();
                    AuthenticationManager manager = (AuthenticationManager)this.getAuthenticationRegistry().build();
                    if (!registry.isNoop() && manager != null) {
                        this.setSharedObject(AuthenticationManager.class, new ObservationAuthenticationManager(registry, manager));
                    } else {
                        this.setSharedObject(AuthenticationManager.class, manager);
                    }
                }
            
            }
            

            说明:此处会向sharedObjects属性中添加一个键值对this.setSharedObject(AuthenticationManager.class, manager);,该managerProviderManager对象

  6. 接口:SecurityConfigurer

    1. 实现类:SecurityConfigurerAdapter

      1. 子类:AbstractHttpConfigurer

        1. 子类:AbstractAuthenticationFilterConfigurer

          1. 属性:private F authFilter;

            说明:authFilter属性的值是UsernamePasswordAuthenticationFilter对象

          2. 构造方法,4️⃣

            protected AbstractAuthenticationFilterConfigurer(F authenticationFilter, String defaultLoginProcessingUrl) {
                this();
                this.authFilter = authenticationFilter;
                if (defaultLoginProcessingUrl != null) {
                    this.loginProcessingUrl(defaultLoginProcessingUrl);
                }
            
            }
            

            说明:

            1. 这里的authenticationFilterUsernamePasswordAuthenticationFilter对象
            2. UsernamePasswordAuthenticationFilter对象会加入到FormLoginConfigurer对象的authFilter属性中
          3. 方法:public void configure(B http),1️⃣1️⃣

            public void configure(B http) throws Exception {
                PortMapper portMapper = (PortMapper)http.getSharedObject(PortMapper.class);
                if (portMapper != null) {
                    this.authenticationEntryPoint.setPortMapper(portMapper);
                }
            
                RequestCache requestCache = (RequestCache)http.getSharedObject(RequestCache.class);
                if (requestCache != null) {
                    this.defaultSuccessHandler.setRequestCache(requestCache);
                }
            
                this.authFilter.setAuthenticationManager((AuthenticationManager)http.getSharedObject(AuthenticationManager.class));
                this.authFilter.setAuthenticationSuccessHandler(this.successHandler);
                this.authFilter.setAuthenticationFailureHandler(this.failureHandler);
                if (this.authenticationDetailsSource != null) {
                    this.authFilter.setAuthenticationDetailsSource(this.authenticationDetailsSource);
                }
            
                SessionAuthenticationStrategy sessionAuthenticationStrategy = (SessionAuthenticationStrategy)http.getSharedObject(SessionAuthenticationStrategy.class);
                if (sessionAuthenticationStrategy != null) {
                    this.authFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
                }
            
                RememberMeServices rememberMeServices = (RememberMeServices)http.getSharedObject(RememberMeServices.class);
                if (rememberMeServices != null) {
                    this.authFilter.setRememberMeServices(rememberMeServices);
                }
            
                SecurityContextConfigurer securityContextConfigurer = (SecurityContextConfigurer)http.getConfigurer(SecurityContextConfigurer.class);
                if (securityContextConfigurer != null && securityContextConfigurer.isRequireExplicitSave()) {
                    SecurityContextRepository securityContextRepository = securityContextConfigurer.getSecurityContextRepository();
                    this.authFilter.setSecurityContextRepository(securityContextRepository);
                }
            
                this.authFilter.setSecurityContextHolderStrategy(this.getSecurityContextHolderStrategy());
                F filter = (AbstractAuthenticationProcessingFilter)this.postProcess(this.authFilter);
                http.addFilter(filter);
            }
            

            说明:this.authFilter.setAuthenticationManager((AuthenticationManager)http.getSharedObject(AuthenticationManager.class));方法中,(AuthenticationManager)http.getSharedObject(AuthenticationManager.class)获取到的是ProviderManager对象,该对象是在HttpSecurity类的beforeConfigure()方法中设置的

          4. 子类:FormLoginConfigurer

            1. 构造方法,3️⃣

              public FormLoginConfigurer() {
                  super(new UsernamePasswordAuthenticationFilter(), (String)null);
                  this.usernameParameter("username");
                  this.passwordParameter("password");
              }
              

              说明:该FormLoginConfigurer对象会加入到HttpSecurity对象的configurers属性中

  7. 抽象类:AbstractAuthenticationProcessingFilter

    1. 属性:private AuthenticationManager authenticationManager;

    2. 方法:public void setAuthenticationManager(AuthenticationManager authenticationManager),1️⃣2️⃣

      public void setAuthenticationManager(AuthenticationManager authenticationManager) {
          this.authenticationManager = authenticationManager;
      }
      

      说明:该authenticationManagerProviderManager对象,会加入到UsernamePasswordAuthenticationFilter对象的authenticationManager属性中

    3. 子类:UsernamePasswordAuthenticationFilter

      1. 构造方法,5️⃣

        public UsernamePasswordAuthenticationFilter() {
            super(DEFAULT_ANT_PATH_REQUEST_MATCHER);
        }
        

        说明:该UsernamePasswordAuthenticationFilter对象会加入到FormLoginConfigurer对象的authFilter属性中

总结

// 伪代码
ProviderManager manager = new ProviderManager();

UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter = new UsernamePasswordAuthenticationFilter();
usernamePasswordAuthenticationFilter.authenticationManager = manager;

FormLoginConfigurer formLoginConfigurer = new FormLoginConfigurer();
formLoginConfigurer.authFilter = usernamePasswordAuthenticationFilter;

HttpSecurity httpSecurity = new HttpSecurity();
httpSecurity.configurers.put(FormLoginConfigurer.class, Arrays.asList(formLoginConfigurer));
httpSecurity.sharedObject.put(AuthenticationManager.class, manager);

如有不对,欢迎指正!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐