spring的security权限真的太香了

907 阅读2分钟

「这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战」

  • 一开始我们解析了WebSecurity的结构图,这时候我们在加入两个同级别的角色AuthenticationManagerBuilderHttpSecurity 。 这两个角色上面都已经出现过了。所以这里更新了下结构图。
  • 相信你读到这里一定晕了,我也很无奈,不过读源码就是这样唯一的方式就是坚持!现在我们想想我们是因为啥走到这一步的。入口是webSecurity.build 。 最终是AbstractConfiguredSecurityBuilder.doBuild开始执行四状态三步骤中的第一步init , init内部执行了WebSecurityConfigurerAdapter#init 。该方法中我们又从getHttp方法进入。在getHttp中需要获取认证管理器。认证管理器需要借助AuthenticationManagerBuilder类型的localConfigureAuthenticationBldr来进行build 。 而通过图示我们知道AuthenticationManagerBuilderWebSecurity拥有相同的图结构。
  • 所以此时为了获取AuthenticationManagerBuilder我们不得不重新执行下AbstractConfiguredSecurityBuilder#doBuild流程。
  • 不说了。我是阵亡了。今天到此结束!明天再来继续往下看!!!!!!

AuthenticationManagerBuilder新开始build

  • 今天我们需要抛开昨天WebSecurity#build的生命周期,因为在websecurity的init阶段就开始了AuthenticationManagerBuilder的build的生命周期了。所以有必要先解决AuthenticationManagerBuilder的生命周期。在build之前我们先看下昨天获取认证管理器的地方

  • 第一步是configure(AuthenticationMangersBuilder) 。 这个是我们配置类中扩展的方法。

auth.inMemoryAuthentication()
  • 点进去内部方法是一个apply方法
public InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> inMemoryAuthentication()
      throws Exception {
   return apply(new InMemoryUserDetailsManagerConfigurer<>());
}
  • 这个apply方法和WebSecurity中一样,将配置赋值给configures 。

  • 这个类和我们SecurityConfig是一样的结构。都是继承SecurityConfigurerAdapter。但是WebSecurity中的configures是WebSecurityConfigurerAdapter . 看源码我们能够知道InMemoryUserDetrailsManagerConfigurer没有实现init方法,所以在AuthenticationMangersBuilder#build中init是空。有了这部分我们在继续开始build操作。

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);
   }
}
  • 因为AuthenticationMangersBuilder的configurers没有实现init , 所以不会产生任何逻辑那么configurersAddedInInitializing也就是空了。所以整体的init没啥逻辑可言。

AuthenticationMangersBuilder中的CONFIGURING状态

  • 随着时间的推移下面我们来到的AuthenticationMangersBuilder#build过程中的CONFIGURING状态了。
private void configure() throws Exception {
   Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();

   for (SecurityConfigurer<O, B> configurer : configurers) {
      configurer.configure((B) this);
   }
}
  • configure方法也很简单,就是执行configures中的configure方法。在这里configures是我们配置的InMemoryUserDetailsManagerConfigurer。还是上面那个结构图他的直系类是UserDetailsManagerConfigurer。最终的configure执行落在UserDetailsServiceConfigurer类上。
@Override
public void configure(B builder) throws Exception {
   initUserDetailsService();

   super.configure(builder);
}
  • initUserDetailsService有落在了UserDetailsManagerConfigurer上。
public final UserDetailsBuilder withUser(String username) {
   UserDetailsBuilder userBuilder = new UserDetailsBuilder((C) this);
   userBuilder.username(username);
   this.userBuilders.add(userBuilder);
   return userBuilder;
}
  • 而上面initUserDetailsService里需要通过userBuilders来创建用户。这个userBuilders正是我们配置类中withUser创建的信息。
  • 然后交由父类AbstractDaoAuthenticationConfigurer#configure来完成。父类里就是对provider进行初始化,初始化的过程也是借助objectPostProcessor来完成。这里就不多做介绍了。
  • 一句话总结AuthenticationMangersBuilder#configure的作用就是加载用户信息,我们的案例就是从内存中加载用户信息。