ethanzhl

V1

2023/01/08阅读:26主题:全栈蓝

Spring Security 启动原理

自动配置

Spring Boot启动时会自动加载 spring.factories 文件中 key 为 EnableAutoConfiguration的配置,其中关于 Spring Security 的配置如下

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,\
......

SecurityAutoConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(DefaultAuthenticationEventPublisher.class)
@EnableConfigurationProperties(SecurityProperties.class)
@Import(
{ SpringBootWebSecurityConfiguration.classWebSecurityEnablerConfiguration.classSecurityDataConfiguration.class })
public class SecurityAutoConfiguration 
{

  @Bean
  @ConditionalOnMissingBean(AuthenticationEventPublisher.class)
  public DefaultAuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher publisher
{
    return new DefaultAuthenticationEventPublisher(publisher);
  }

}

这里主要干了三件事

  1. 加载了SecurityProperties配置文件
  2. 导入了三个配置类
  3. 创建一个默认的认证事件发布器 DefaultAuthenticationEventPublisher

SpringBootWebSecurityConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
@ConditionalOnWebApplication(type 
= Type.SERVLET)
public class SpringBootWebSecurityConfiguration {

  @Configuration(proxyBeanMethods = false)
  @Order(SecurityProperties.BASIC_AUTH_ORDER)
  static class DefaultConfigurerAdapter extends WebSecurityConfigurerAdapter {

  }

}

在开发者没有提供 WebSecurityConfigurerAdapter实例的情况下,提供一个默认的实例 DefaultConfigurerAdapter

SecurityDataConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(SecurityEvaluationContextExtension.class)
public class SecurityDataConfiguration 
{

  @Bean
  @ConditionalOnMissingBean
  public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
    return new SecurityEvaluationContextExtension();
  }

}

在开发者没有提供SecurityEvaluationContextExtension实例的情况下,提供一个实例 SecurityEvaluationContextExtension

WebSecurityEnablerConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(WebSecurityConfigurerAdapter.class)
@ConditionalOnMissingBean(name 
= BeanIds.SPRING_SECURITY_FILTER_CHAIN)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@EnableWebSecurity
public class WebSecurityEnablerConfiguration {

}

配置类引入了一个注解@EnableWebSecurity

@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = { java.lang.annotation.ElementType.TYPE })
@Documented
@Import({ WebSecurityConfiguration.classSpringWebMvcImportSelector.classOAuth2ImportSelector.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity 
{

  boolean debug() default false;
  
}
  1. @EnableWebSecurity是一个组合注解,导入了三个配置类
    • WebSecurityConfiguration用来配置WebScrurity
    • SpringWebMvcImportSelector判断当前环境是否存在Spring MVC,如果存在,则引入相关配置
    • OAuth2ImportSelector判断当前环境是否存在OAuth2,如果存在,则引入相关配置
  2. @EnableGlobalAuthentication导入了配置类AuthenticationConfiguration

Spring Security 的自动化配置主要倒入了两个配置类 WebSecurityConfigurationAuthenticationConfiguration

WebSecurityConfiguration

WebSecurityConfiguration的主要功能就是为了构建 Spring Security 过滤器链代理对象 FilterChainProxy,FilterChainProxy是由WebSecurity 来构建的,所以在WebSecurityConfiguration中首先会构建WebSecurity对象,再由 WebSecurity 对象构建FilterChainProxy

AutowiredWebSecurityConfigurersIgnoreParents

final class AutowiredWebSecurityConfigurersIgnoreParents {

  private final ConfigurableListableBeanFactory beanFactory;

  AutowiredWebSecurityConfigurersIgnoreParents(ConfigurableListableBeanFactory beanFactory) {
    Assert.notNull(beanFactory, "beanFactory cannot be null");
    this.beanFactory = beanFactory;
  }

  @SuppressWarnings({ "rawtypes""unchecked" })
  public List<SecurityConfigurer<Filter, WebSecurity>> `getWebSecurityConfigurers`() {
    List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new ArrayList<>();
    Map<String, WebSecurityConfigurer> beansOfType = beanFactory.getBeansOfType(WebSecurityConfigurer.class);
    for (Entry<String, WebSecurityConfigurer> entry : beansOfType.entrySet()) {
      webSecurityConfigurers.add(entry.getValue());
    }
    return webSecurityConfigurers;
  }
}

getWebSecurityConfigurers()方法中主要通过调用beanFactory.getBeansOfType(WebSecurityConfigurer.class)方法来获取Spring容器中所有的WebSecurityConfigurer实例,也就是开发者自定义的各种继承至WebSecurityConfigurerAdapter的配置类,如果开发者没有定义任何自定义的配置类,这里获取到的就是前面SpringBootWebSecurityConfiguration类中提供的默认配置类DefaultConfigurerAdapter

  • setFilterChainProxySecurityConfigurer()
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
    @Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}")
 
    List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers) throws Exception 
{
    
  // 1、创建创建了一个 WebSecurity,经过后置处理器处理之后加入到spring容器中
  webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
  if (debugEnabled != null) {
    webSecurity.debug(debugEnabled);
  }
  
  // 2、对配置类进行排序
  webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);

  Integer previousOrder = null;
  Object previousConfig = null;
  for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {
    Integer order = AnnotationAwareOrderComparator.lookupOrder(config);
    if (previousOrder != null && previousOrder.equals(order)) {
      throw new IllegalStateException(
          "@Order on WebSecurityConfigurers must be unique. Order of "
              + order + " was already used on " + previousConfig + ", so it cannot be used on "
              + config + " too.");
    }
    previousOrder = order;
    previousConfig = config;
  }
  
  // 3、遍历配置类,将其加入到`WebSecurity`父类的configurers集合中(将来遍历该集合并分别调用配置类的`init`和`configure`方法完成配置类的初始化和配置操作)
  for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
    webSecurity.apply(webSecurityConfigurer);
  }
  
  // 4、缓存配置类列表
  this.webSecurityConfigurers = webSecurityConfigurers;
}

该方法主要用来初始化WebSecurity对象,同时收集到所有的自定义配置类

  • springSecurityFilterChain()
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
  boolean hasConfigurers = webSecurityConfigurers != null && !webSecurityConfigurers.isEmpty();
  if (!hasConfigurers) {
    WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor.postProcess(new WebSecurityConfigurerAdapter() {});
    webSecurity.apply(adapter);
  }
  return webSecurity.build();
}

这里首先判断webSecurityConfigurers集合中是否存在配置类,如果不存在,则创建一个匿名的WebSecurityConfigurerAdapter并注册到 Spring 容器中,否则,直接调用 WebSecuritybuild方法进行构建。

  • WebSecurity#build()
classDiagram
      AbstractSecurityBuilder~O~ <|-- AbstractConfiguredSecurityBuilder~O,B~
      AbstractConfiguredSecurityBuilder <|-- WebScurity
      SecurityConfigurer~O,B extends SecurityBuilder~ <|-- WebSecurityConfigurer~WebScurity~
      WebSecurityConfigurer~WebScurity~ <|.. WebSecurityConfigurerAdapter
      
      class AbstractSecurityBuilder {
          +O build()
          #O doBuild()
      }
      
      class AbstractConfiguredSecurityBuilder {
          #O doBuild()
          -void init()
          -void configure()
          #O performBuild()
      }
      
        class WebScurity {
          #Filter performBuild()
      }
      
      class SecurityConfigurer {
        +void init()
        +void configure()
      }
      
      class WebSecurityConfigurer {
        +void init()
        +void configure()
      }
      
      class WebSecurityConfigurerAdapter {
        +void configure(WebSecurity web)
      }

WebScuritybuild方法最终会调用父类AbstractConfiguredSecurityBuilderdoBuild方法

@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;
  }
}

doBuild方法中调用initconfigureperformBuild方法

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);
    }
  }
  
  protected abstract O performBuild() throws Exception;

WebSecurityConfigurerAdapter 中实现了 initconfigure方法

public void init(final WebSecurity web) throws Exception {
  final HttpSecurity http = getHttp();
  web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {
    FilterSecurityInterceptor securityInterceptor = http
        .getSharedObject(FilterSecurityInterceptor.class);
    web.securityInterceptor(securityInterceptor);
  });
}

// 子类可以重写该方法实现自定义逻辑
public void configure(WebSecurity web) throws Exception {
  
}

// 子类可以重写该方法实现自定义逻辑
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  this.disableLocalConfigureAuthenticationBldr = true;
}

// 子类可以重写该方法实现自定义逻辑
protected void configure(HttpSecurity http) throws Exception {
  logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");

  http
    .authorizeRequests()
    .anyRequest().authenticated()
    .and()
    .formLogin()
    .and()
    .httpBasic();
}

AuthenticationManagerBuilderHttpSecurityWebSecurity分别都重写 performBuild方法

public class AuthenticationManagerBuilder {

  ......
  
  @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;
  }
}


public final class HttpSecurity {

  ......
  
  @Override
  protected DefaultSecurityFilterChain performBuild() {
    filters.sort(comparator);
    return new DefaultSecurityFilterChain(requestMatcher, filters);
  }
}


public final class WebSecurity {

  ......
  
  @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<SecurityFilterChain> 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);
    }
    postBuildAction.run();
    return result;
  }
}

AuthenticationConfiguration

在Spring Security 自动化配置类中导入的另一配置类是AuthenticationConfiguration,该类的功能主要是做全局配置,同时提供一个全局的AuthticationManager实例。

@Configuration(proxyBeanMethods = false)
@Import(ObjectPostProcessorConfiguration.class)
public class AuthenticationConfiguration 
{
  ......
}

导入了一个配置类ObjectPostProcessorConfiguration

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ObjectPostProcessorConfiguration {

  @Bean
  @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
  public ObjectPostProcessor<Object> objectPostProcessor(
      AutowireCapableBeanFactory beanFactory)
 
{
    return new AutowireBeanFactoryObjectPostProcessor(beanFactory);
  }
}

ObjectPostProcessorConfiguration配置类主要提供了一个后置对象处理器ObjectPostProcessor实例, 具体实现类是AutowireBeanFactoryObjectPostProcessor,该实例主要用来将一个对象注册到Spring容器中去,其他配置类中所见到的ObjectPostProcessor实例就是这里提供的。

@Configuration(proxyBeanMethods = false)
@Import(ObjectPostProcessorConfiguration.class)
public class AuthenticationConfiguration 
{
  ......
  
  @Bean
  public AuthenticationManagerBuilder authenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor, ApplicationContext context) {
    LazyPasswordEncoder defaultPasswordEncoder = new LazyPasswordEncoder(context);
    AuthenticationEventPublisher authenticationEventPublisher = getBeanOrNull(context, AuthenticationEventPublisher.class);

    DefaultPasswordEncoderAuthenticationManagerBuilder result = new DefaultPasswordEncoderAuthenticationManagerBuilder(objectPostProcessor, defaultPasswordEncoder);
    if (authenticationEventPublisher != null) {
      result.authenticationEventPublisher(authenticationEventPublisher);
    }
    return result;
  }
  
  @Bean
  public static GlobalAuthenticationConfigurerAdapter enableGlobalAuthenticationAutowiredConfigurer(
      ApplicationContext context)
 
{
    return new EnableGlobalAuthenticationAutowiredConfigurer(context);
  }
  
  @Bean
  public static InitializeUserDetailsBeanManagerConfigurer initializeUserDetailsBeanManagerConfigurer(ApplicationContext context) {
    return new InitializeUserDetailsBeanManagerConfigurer(context);
  }

  @Bean
  public static InitializeAuthenticationProviderBeanManagerConfigurer initializeAuthenticationProviderBeanManagerConfigurer(ApplicationContext context) {
    return new InitializeAuthenticationProviderBeanManagerConfigurer(context);
  }
  
  public AuthenticationManager getAuthenticationManager() throws Exception {
    if (this.authenticationManagerInitialized) {
      return this.authenticationManager;
    }
    AuthenticationManagerBuilder authBuilder = this.applicationContext.getBean(AuthenticationManagerBuilder.class);
    if (this.buildingAuthenticationManager.getAndSet(true)) {
      return new AuthenticationManagerDelegator(authBuilder);
    }

    for (GlobalAuthenticationConfigurerAdapter config : globalAuthConfigurers) {
      authBuilder.apply(config);
    }

    authenticationManager = authBuilder.build();

    if (authenticationManager == null) {
      authenticationManager = getAuthenticationManagerBean();
    }

    this.authenticationManagerInitialized = true;
    return authenticationManager;
  }
  
  @Autowired(required = false)
  public void setGlobalAuthenticationConfigurers(
      List<GlobalAuthenticationConfigurerAdapter> configurers)
 
{
    configurers.sort(AnnotationAwareOrderComparator.INSTANCE);
    this.globalAuthConfigurers = configurers;
  }

  @Autowired
  public void setApplicationContext(ApplicationContext applicationContext) {
    this.applicationContext = applicationContext;
  }

  @Autowired
  public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
    this.objectPostProcessor = objectPostProcessor;
  }
  
  ......
}
  1. 首先定义了一个AuthenticationManagerBuilder实例,目的是为了构建全局的AuthticationManager对象
  2. 接下来构建了3个Bean
    • InitializeAuthenticationProviderBeanManagerConfigurer初始化全集的AuthticationProvider对象
    • InitializeUserDetailsBeanManagerConfigurer初始化全局的UserDetailsService对象
    • EnableGlobalAuthenticationAutowiredConfigurer从Spring容器中加载被@EnableGlobalAuthentication注解标记的Bean
  3. getAuthenticationManager()方法则用来构建具体的AuthenticationManager对象
    • 判断AuthenticationManager是否已经初始化,如果已经初始化,则直接返回AuthenticationManager对象
    • 否则就先从Spring容器中获取AuthenticationManagerBuilder对象
    • AuthenticationManagerDelegator实现AuthenticactionManager接口,主要是为了防止在初始化AuthenticationManager时进行无限递归
    • 拿到AuthenticationManagerBuilder对象后,遍历globalAuthConfigurers配置类集合(也就是第二点所说的三个配置类),将配置类分别添加到AuthenticationManagerBuilder对象父类的 configurers集合中
  4. 进行构建,返回结果

🔼 整体来说AuthticationConfiguration的作用主要体现在两个方面:

  • 导入了ObjectPostProcessorConfiguration配置类
  • 提供了一个全局的AuthenticationManager对象

如果开发这在自定义的配置类中重写了configure(AuthenticationBuilder builder) 方法,这里的全局AuthenticationManager将不会生效

public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigurer<WebSecurity{
  ......
  
  // 如果重写该方法,`disableLocalConfigureAuthenticationBldr`的值将还是默认初始化的false
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    this.`disableLocalConfigureAuthenticationBldr` = true;
  }
  
  protected AuthenticationManager authenticationManager() throws Exception {
    if (!authenticationManagerInitialized) {
      configure(localConfigureAuthenticationBldr);
      if (`disableLocalConfigureAuthenticationBldr`) {
        // 这里的`authenticationConfiguration`就是上面说的全局配置类
        authenticationManager = `authenticationConfiguration`.getAuthenticationManager();
      }
      else {
        authenticationManager = localConfigureAuthenticationBldr.build();
      }
      authenticationManagerInitialized = true;
    }
    return authenticationManager;
  }
  
  ......
}

SecurityFilterAutoConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(SecurityProperties.class)
@ConditionalOnClass(
{ AbstractSecurityWebApplicationInitializer.classSessionCreationPolicy.class })
@AutoConfigureAfter(SecurityAutoConfiguration.class)
public class SecurityFilterAutoConfiguration 
{

  private static final String DEFAULT_FILTER_NAME = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME;

  @Bean
  @ConditionalOnBean(name = DEFAULT_FILTER_NAME)
  public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(SecurityProperties securityProperties) {
    DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(DEFAULT_FILTER_NAME);
    
    registration.setOrder(securityProperties.getFilter().getOrder());
    registration.setDispatcherTypes(getDispatcherTypes(securityProperties));
    
    return registration;
  }

  private EnumSet<DispatcherType> getDispatcherTypes(SecurityProperties securityProperties) {
    if (securityProperties.getFilter().getDispatcherTypes() == null) {
      return null;
    }
    return securityProperties.getFilter().getDispatcherTypes().stream()
        .map((type) -> DispatcherType.valueOf(type.name()))
        .collect(Collectors.toCollection(() -> EnumSet.noneOf(DispatcherType.class)));
  }

}

SecurityFilterAutoConfiguration配置类提供了一个DelegatingFilterProxyRegistrationBean实例,此时DelegatingFilterProxyRegistrationBean对象的属性targetBeanName的值为 "springSecurityFilterChain"

UserDetailsServiceAutoConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(AuthenticationManager.class)
@ConditionalOnBean(ObjectPostProcessor.class)
@ConditionalOnMissingBean(
    value 
= { AuthenticationManager.classAuthenticationProvider.classUserDetailsService.class },
    type 
= { "org.springframework.security.oauth2.jwt.JwtDecoder",
             "org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector" })
public class UserDetailsServiceAutoConfiguration {

  private static final String NOOP_PASSWORD_PREFIX = "{noop}";

  private static final Pattern PASSWORD_ALGORITHM_PATTERN = Pattern.compile("^\\{.+}.*$");

  private static final Log logger = LogFactory.getLog(UserDetailsServiceAutoConfiguration.class);

  @Bean
  @ConditionalOnMissingBean(type = "org.springframework.security.oauth2.client.registration.ClientRegistrationRepository")
  @Lazy
  public InMemoryUserDetailsManager inMemoryUserDetailsManager(SecurityProperties properties, ObjectProvider<PasswordEncoder> passwordEncoder) {
    SecurityProperties.User user = properties.getUser();
    List<String> roles = user.getRoles();
    return new InMemoryUserDetailsManager(
        User.withUsername(user.getName())
            .password(getOrDeducePassword(user, passwordEncoder.getIfAvailable()))
            .roles(StringUtils.toStringArray(roles)).build());
  }

  private String getOrDeducePassword(SecurityProperties.User user, PasswordEncoder encoder) {
    String password = user.getPassword();
    if (user.isPasswordGenerated()) {
      logger.info(String.format("%n%nUsing generated security password: %s%n", user.getPassword()));
    }
    if (encoder != null || PASSWORD_ALGORITHM_PATTERN.matcher(password).matches()) {
      return password;
    }
    return NOOP_PASSWORD_PREFIX + password;
  }

}

主要提供了一个默认的基于内存的InMemoryUserDetailsManager用户信息管理器,并利用SecurityProperties中定义的默认用户,创建一个默认的用户账号,可以通过提供AuthenticationManager、AuthenticationProvider、UserDetailsService的bean来覆盖默认配置。

流程分析

WebSecurityConfiguration

该配置类中setFilterChainProxySecurityConfigurer方法主要做了如下事情:

  1. 提供了一个AutowiredWebSecurityConfigurersIgnoreParents实例对象
  2. setFilterChainProxySecurityConfigurer方法中调用 1 中的AutowiredWebSecurityConfigurersIgnoreParents实例对象的getWebSecurityConfigurers方法得到用户自定义的所有继承自WebSecurityConfigurerAdapter实例对象集合,如果没有自定义对象,这里得到的就是Spring Security提供的默认的DefaultConfigurerAdapter实例对象
  3. 创建了一个WebSecurity对象,调用AutowireBeanFactoryObjectPostProcessor实例的postProcess方法将WebSecurity对象注册到Spring容器中
  4. 遍历2中得到的用户自定义WebSecurityConfigurerAdapter子类集合,添加到WebSecurity父类的configurers集合中
  5. springSecurityFilterChain方法中调用WebSecuritybuild方法,实际调用的是WebSecurity父类的doBuild方法,在doBuild方法中,遍历2中得到的自定义配置类集合,调用initconfigure方法,执行初始化及配置逻辑
  6. WebSecurityConfigurerAdapter子类在调用init方法初始化时,先调用getHttp,执行authenticationManager方法,根据子类是否重写configure(AuthenticationManagerBuilder auth)方法,判断是否需要调用AuthenticationConfigurationgetAuthenticationManager方法获得一个全局的AuthenticationManager实例对象,给局部创建的AuthenticationManager设置父AuthenticationManagerauthenticationManager方法的返回值,然后创建一个HttpSecurity对象,并设置AutowireBeanFactoryObjectPostProcessor后置处理器对象及局部的AuthenticationManager对象,返回HttpSecurity对象
  7. init的初始化的下一步是拿到6 返回的HttpSecurity对象,并添加到WebSecurity中的securityFilterChainBuilders集合中
  8. configure方法没做任何操作,留给子类可以重写该方法实现自定义的逻辑
  9. 最后执行WebSecurity对象 的performBuild方法,该方法会遍历securityFilterChainBuilders集合,执行SecurityBuilderbuild方法,此时的SecurityBuilder实际为7中添加的HttpSecurity实例对象,而HttpSecurity类定义中这样写到public final class HttpSecurity implements SecurityBuilder<DefaultSecurityFilterChain>,由此可见,HttpSecurity对象的build实际会创建一个DefaultSecurityFilterChain默认过滤器链对象,回到WebSecurity对象 的performBuild方法,得到DefaultSecurityFilterChain并添加到securityFilterChains集合中,接下来创建一个FilterChainProxy对象,在构造方法中设置其filterChains集合属性值为上面得到的securityFilterChains过滤器链集合,返回FilterChainProxy实例对象
  10. 至此WebSecurityConfiguration中的springSecurityFilterChain方法才算执行完毕,得到一个包含过滤器链列表的FilterChainProxy实例对象,并将FilterChainProxy对象注册到Spring容器中,beannamespringSecurityFilterChain

WebSecurity

WebSecurity是由WebSecurityConfiguration创建的,用来创建FilterChainProxy,也就是SpringSecurityFilterChain (springSecurityFilterChain)。springSecurityFilterChainDelegatingFilterProxy委托的Filter。 对WebSecurity的自定义可以通过创建WebSecurityConfigurer或者更可能的是通过覆盖WebSecurityConfigurerAdapter来实现,WebSecurity在build中会为每个WebSecurityConfigurerAdapter子类生成一个过滤器链DefaultSecurityFilterChain,其中的filter列表为HttpSecurity构建过程中,遍历父类configurers,执行配置类的configure方法得到的Filter对象。

WebSecurityConfigurerAdapter

为创建WebSecurityConfigurer实例提供了一个方便的基类。该实现允许通过重写方法进行定制。 将自动应用从SpringFactoriesLoader中查找AbstractHttpConfigurer的结果,以允许开发人员扩展默认值。为此,您必须创建一个扩展AbstractHttpConfigurer的类,然后在类路径下中创建“META-INF/spring.factories”文件

init

  • 调用getHttp方法
    • 调用authenticationManager方法,创建一个AuthenticationManager实例对象ProviderManager
      • 根据disableLocalConfigureAuthenticationBldr判断是否禁止本地配置AuthenticationManagerBuilder
      • 执行AuthenticationManagerBuilderbuild方法
        • 执行performBuild方法
          • 创建一个ProviderManager对象,保存开发者添加的AuthenticationProvider,在对象后置处理器中处理一遍,将ProviderManager注册到Spring容器中
    • 设置本地创建的AuthenticationManagerBuilder对象的父类为上面生成的ProviderManager实例对象
    • 创建共享对象集合sharedObjects
sharedObjects.putAll(localConfigureAuthenticationBldr.getSharedObjects());
sharedObjects.put(UserDetailsService.classuserDetailsService());
sharedObjects.put(ApplicationContext.classcontext);
sharedObjects.put(ContentNegotiationStrategy.classcontentNegotiationStrategy);
sharedObjects.put(AuthenticationTrustResolver.classtrustResolver);
// 在HttpSecurity构造方法中进行设置
sharedObjects.put(AuthenticationManagerBuilder.classauthenticationBuilder);

分类:

后端

标签:

Java

作者介绍

ethanzhl
V1