溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么理解SecurityConfigurer

發(fā)布時(shí)間:2021-10-29 17:32:14 來(lái)源:億速云 閱讀:148 作者:iii 欄目:web開發(fā)

這篇文章主要講解了“怎么理解SecurityConfigurer”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“怎么理解SecurityConfigurer”吧!

1. SecurityConfigurerSecurityConfigurer

本身是一個(gè)接口,我們來(lái)看下:

public interface SecurityConfigurer<O, B extends SecurityBuilder<O>> {   void init(B builder) throws Exception;   void configure(B builder) throws Exception; }

可以看到,SecurityConfigurer 中主要是兩個(gè)方法,init 和 configure。

init 就是一個(gè)初始化方法。而 configure 則是一個(gè)配置方法。這里只是規(guī)范了方法的定義,具體的實(shí)現(xiàn)則在不同的實(shí)現(xiàn)類中。

需要注意的是這兩個(gè)方法的參數(shù)類型都是一個(gè)泛型 B,也就是 SecurityBuilder 的子類,關(guān)于 SecurityBuilder  ,它是用來(lái)構(gòu)建過(guò)濾器鏈的,松哥將在下篇文章中和大家介紹。

SecurityConfigurer 有三個(gè)實(shí)現(xiàn)類:

  • SecurityConfigurerAdapter

  • GlobalAuthenticationConfigurerAdapter

  • WebSecurityConfigurer

我們分別來(lái)看。

1.1 SecurityConfigurerAdapter

SecurityConfigurerAdapter實(shí)現(xiàn)了 SecurityConfigurer  接口,我們所使用的大部分的 xxxConfigurer 也都是 SecurityConfigurerAdapter 的子類。

SecurityConfigurerAdapter 在 SecurityConfigurer  的基礎(chǔ)上,還擴(kuò)展出來(lái)了幾個(gè)非常好用的方法,我們一起來(lái)看下:

public abstract class SecurityConfigurerAdapter<O, B extends SecurityBuilder<O>>   implements SecurityConfigurer<O, B> {  private B securityBuilder;   private CompositeObjectPostProcessor objectPostProcessor = new CompositeObjectPostProcessor();   public void init(B builder) throws Exception {  }   public void configure(B builder) throws Exception {  }   public B and() {   return getBuilder();  }  protected final B getBuilder() {   if (securityBuilder == null) {    throw new IllegalStateException("securityBuilder cannot be null");   }   return securityBuilder;  }  @SuppressWarnings("unchecked")  protected <T> T postProcess(T object) {   return (T) this.objectPostProcessor.postProcess(object);  }  public void addObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {   this.objectPostProcessor.addObjectPostProcessor(objectPostProcessor);  }  public void setBuilder(B builder) {   this.securityBuilder = builder;  }  private static final class CompositeObjectPostProcessor implements    ObjectPostProcessor<Object> {   private List<ObjectPostProcessor<?>> postProcessors = new ArrayList<>();    @SuppressWarnings({ "rawtypes", "unchecked" })   public Object postProcess(Object object) {    for (ObjectPostProcessor opp : postProcessors) {     Class<?> oppClass = opp.getClass();     Class<?> oppType = GenericTypeResolver.resolveTypeArgument(oppClass,       ObjectPostProcessor.class);     if (oppType == null || oppType.isAssignableFrom(object.getClass())) {      object = opp.postProcess(object);     }    }    return object;   }   private boolean addObjectPostProcessor(     ObjectPostProcessor<?> objectPostProcessor) {    boolean result = this.postProcessors.add(objectPostProcessor);    postProcessors.sort(AnnotationAwareOrderComparator.INSTANCE);    return result;   }  } }
  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. CompositeObjectPostProcessor 首先一開始聲明了一個(gè) CompositeObjectPostProcessor  實(shí)例,CompositeObjectPostProcessor 是 ObjectPostProcessor 的一個(gè)實(shí)現(xiàn),ObjectPostProcessor  本身是一個(gè)后置處理器,該后置處理器默認(rèn)有兩個(gè)實(shí)現(xiàn),AutowireBeanFactoryObjectPostProcessor 和  CompositeObjectPostProcessor。其中 AutowireBeanFactoryObjectPostProcessor 主要是利用了  AutowireCapableBeanFactory 對(duì) Bean 進(jìn)行手動(dòng)注冊(cè),因?yàn)樵?Spring Security 中,很多對(duì)象都是手動(dòng) new  出來(lái)的,這些 new 出來(lái)的對(duì)象和容器沒(méi)有任何關(guān)系,利用 AutowireCapableBeanFactory 可以將這些手動(dòng) new  出來(lái)的對(duì)象注入到容器中,而 AutowireBeanFactoryObjectPostProcessor  的主要作用就是完成這件事;CompositeObjectPostProcessor 則是一個(gè)復(fù)合的對(duì)象處理器,里邊維護(hù)了一個(gè) List 集合,這個(gè) List  集合中,大部分情況下只存儲(chǔ)一條數(shù)據(jù),那就是  AutowireBeanFactoryObjectPostProcessor,用來(lái)完成對(duì)象注入到容器的操作,如果用戶自己手動(dòng)調(diào)用了  addObjectPostProcessor 方法,那么 CompositeObjectPostProcessor 集合中維護(hù)的數(shù)據(jù)就會(huì)多出來(lái)一條,在  CompositeObjectPostProcessor#postProcess 方法中,會(huì)遍歷集合中的所有 ObjectPostProcessor,挨個(gè)調(diào)用其  postProcess 方法對(duì)對(duì)象進(jìn)行后置處理。

  3. and 方法,該方法返回值是一個(gè) securityBuilder,securityBuilder  實(shí)際上就是 HttpSecurity,我們?cè)?HttpSecurity 中去配置不同的過(guò)濾器時(shí),可以使用 and 方法進(jìn)行鏈?zhǔn)脚渲茫褪且驗(yàn)檫@里定義了 and  方法并返回了 securityBuilder 實(shí)例。

這便是 SecurityConfigurerAdapter 的主要功能,后面大部分的  xxxConfigurer 都是基于此類來(lái)實(shí)現(xiàn)的。

1.2  GlobalAuthenticationConfigurerAdapter

GlobalAuthenticationConfigurerAdapter  看名字就知道是一個(gè)跟全局配置有關(guān)的東西,它本身實(shí)現(xiàn)了 SecurityConfigurerAdapter  接口,但是并未對(duì)方法做具體的實(shí)現(xiàn),只是將泛型具體化了:

@Order(100) public abstract class GlobalAuthenticationConfigurerAdapter implements   SecurityConfigurer<AuthenticationManager, AuthenticationManagerBuilder> {   public void init(AuthenticationManagerBuilder auth) throws Exception {  }   public void configure(AuthenticationManagerBuilder auth) throws Exception {  } }

可以看到,SecurityConfigurer 中的泛型,現(xiàn)在明確成了 AuthenticationManager 和  AuthenticationManagerBuilder。所以 GlobalAuthenticationConfigurerAdapter  的實(shí)現(xiàn)類將來(lái)主要是和配置 AuthenticationManager 有關(guān)。當(dāng)然也包括默認(rèn)的用戶名密碼也是由它的實(shí)現(xiàn)類來(lái)進(jìn)行配置的。

我們?cè)? Spring Security 中使用的 AuthenticationManager  其實(shí)可以分為兩種,一種是局部的,另一種是全局的,這里主要是全局的配置。

1.3 WebSecurityConfigurer

還有一個(gè)實(shí)現(xiàn)類就是  WebSecurityConfigurer,這個(gè)可能有的小伙伴比較陌生,其實(shí)他就是我們天天用的 WebSecurityConfigurerAdapter  的父接口。

所以 WebSecurityConfigurer 的作用就很明確了,用戶擴(kuò)展用戶自定義的配置。

SecurityConfigurer 默認(rèn)主要是這三個(gè)實(shí)現(xiàn),考慮到大多數(shù)的過(guò)濾器配置都是通過(guò) SecurityConfigurerAdapter  進(jìn)行擴(kuò)展的,因此我們今天就通過(guò)這條線進(jìn)行展開。另外兩條線松哥也將擼兩篇文章和大家介紹。

2.  SecurityConfigurerAdapter

SecurityConfigurerAdapter 的實(shí)現(xiàn)主要也是三大類:

  • UserDetailsAwareConfigurer

  • AbstractHttpConfigurer

  • LdapAuthenticationProviderConfigurer

考慮到 LDAP  現(xiàn)在使用很少,所以這里我來(lái)和大家重點(diǎn)介紹下前兩個(gè)。

2.1  UserDetailsAwareConfigurer

這個(gè)配置類看名字大概就知道這是用來(lái)配置用戶類的。

怎么理解SecurityConfigurer

AbstractDaoAuthenticationConfigurer

AbstractDaoAuthenticationConfigurer  中所做的事情比較簡(jiǎn)單,主要是構(gòu)造了一個(gè)默認(rèn)的 DaoAuthenticationProvider,并為其配置 PasswordEncoder 和  UserDetailsService。

UserDetailsServiceConfigurer

UserDetailsServiceConfigurer 重寫了 AbstractDaoAuthenticationConfigurer 中的  configure 方法,在 configure 方法執(zhí)行之前加入了 initUserDetailsService 方法,以方便開發(fā)展按照自己的方式去初始化  UserDetailsService。不過(guò)這里的 initUserDetailsService 方法是空方法。

UserDetailsManagerConfigurer

UserDetailsManagerConfigurer 中實(shí)現(xiàn)了  UserDetailsServiceConfigurer 中定義的 initUserDetailsService 方法,具體的實(shí)現(xiàn)邏輯就是將  UserDetailsBuilder 所構(gòu)建出來(lái)的 UserDetails 以及提前準(zhǔn)備好的 UserDetails 中的用戶存儲(chǔ)到  UserDetailsService 中。

該類同時(shí)添加了 withUser 方法用來(lái)添加用戶,同時(shí)還增加了一個(gè)  UserDetailsBuilder 用來(lái)構(gòu)建用戶,這些邏輯都比較簡(jiǎn)單,小伙伴們可以自行查看。

JdbcUserDetailsManagerConfigurer

JdbcUserDetailsManagerConfigurer  在父類的基礎(chǔ)上補(bǔ)充了 DataSource 對(duì)象,同時(shí)還提供了相應(yīng)的數(shù)據(jù)庫(kù)查詢方法。

InMemoryUserDetailsManagerConfigurer

InMemoryUserDetailsManagerConfigurer 在父類的基礎(chǔ)上重寫了構(gòu)造方法,將父類中的 UserDetailsService  實(shí)例定義為 InMemoryUserDetailsManager。

DaoAuthenticationConfigurer

DaoAuthenticationConfigurer 繼承自  AbstractDaoAuthenticationConfigurer,只是在構(gòu)造方法中修改了一下 userDetailsService 而已。

有小伙伴可能要問(wèn)了,JdbcUserDetailsManagerConfigurer 或者  InMemoryUserDetailsManagerConfigurer,到底在哪里可以用到呀?

松哥給大家舉一個(gè)簡(jiǎn)單的例子:

@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter {      @Override     protected void configure(AuthenticationManagerBuilder auth) throws Exception {         auth.inMemoryAuthentication().withUser("javaboy")                 .password("{noop}123")                 .roles("admin");     }      @Override     protected void configure(HttpSecurity http) throws Exception {         http.authorizeRequests()                 .anyRequest().authenticated()                 //省略     } }

當(dāng)你調(diào)用 auth.inMemoryAuthentication 進(jìn)行配置時(shí),實(shí)際上調(diào)用的就是  InMemoryUserDetailsManagerConfigurer。

這下明白了吧!

2.2  AbstractHttpConfigurer

AbstractHttpConfigurer  這一派中的東西非常多,我們所有的過(guò)濾器配置,都是它的子類,我們來(lái)看下都有哪些類?

怎么理解SecurityConfigurer

可以看到,它的實(shí)現(xiàn)類還是非常多的。

這么多實(shí)現(xiàn)類,松哥就不一一給大家介紹了,我挑一個(gè)常用的 FormLoginConfigurer  來(lái)給大家詳細(xì)介紹,只要大家把這個(gè)理解了,其他的照貓畫虎就很好理解了。

我們一個(gè)一個(gè)來(lái)看。

2.2.1  AbstractHttpConfigurer

AbstractHttpConfigurer 繼承自  SecurityConfigurerAdapter,并增加了兩個(gè)方法,disable 和 withObjectPostProcessor:

public abstract class AbstractHttpConfigurer<T extends AbstractHttpConfigurer<T, B>, B extends HttpSecurityBuilder<B>>   extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, B> {   /**   * Disables the {@link AbstractHttpConfigurer} by removing it. After doing so a fresh   * version of the configuration can be applied.   *   * @return the {@link HttpSecurityBuilder} for additional customizations   */  @SuppressWarnings("unchecked")  public B disable() {   getBuilder().removeConfigurer(getClass());   return getBuilder();  }   @SuppressWarnings("unchecked")  public T withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {   addObjectPostProcessor(objectPostProcessor);   return (T) this;  } }

這兩個(gè)方法松哥之前都有給大家介紹過(guò),disable 基本上是大家的老熟人了,我們常用的 .csrf().disable()  就是出自這里,那么從這里我們也可以看到 disable 的實(shí)現(xiàn)原理,就是從 getBuilder 中移除相關(guān)的 xxxConfigurer,getBuilder  方法獲取到的實(shí)際上就是 HttpSecurity,所以移除掉 xxxConfigurer 實(shí)際上就是從過(guò)濾器鏈中移除掉某一個(gè)過(guò)濾器,例如  .csrf().disable() 就是移除掉處理 csrf 的過(guò)濾器。

另一個(gè)增加的方法是  withObjectPostProcessor,這是為配置類添加手動(dòng)添加后置處理器的。在 AbstractHttpConfigurer  的父類中其實(shí)有一個(gè)類似的方法就是 addObjectPostProcessor,但是 addObjectPostProcessor 只是一個(gè)添加方法,返回值為  void,而 withObjectPostProcessor 的返回值是當(dāng)前配置類,也就是 xxxConfigurer,所以如果使用  withObjectPostProcessor 的話,可以使用鏈?zhǔn)脚渲茫聦?shí)上,在松哥之前的文章,以及  vhr(https://github.com/lenve/vhr) 項(xiàng)目中,使用的也都是 withObjectPostProcessor  方法(當(dāng)然,你也可以使用 addObjectPostProcessor,最終效果是一樣的)。

2.2.2  AbstractAuthenticationFilter

ConfigurerAbstractAuthenticationFilterConfigurer  類的功能比較多,源碼也是相當(dāng)相當(dāng)長(zhǎng)。不過(guò)我們只需要抓住兩點(diǎn)即可,init 方法和 configure 方法,因?yàn)檫@兩個(gè)方法是所有 xxxConfigurer  的靈魂。

@Override public void init(B http) throws Exception {  updateAuthenticationDefaults();  updateAccessDefaults(http);  registerDefaultAuthenticationEntryPoint(http); }

init 方法主要干了三件事:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. updateAuthenticationDefaults 主要是配置了登錄處理地址,失敗跳轉(zhuǎn)地址,注銷成功跳轉(zhuǎn)地址。

  3. updateAccessDefaults 方法主要是對(duì) loginPage、loginProcessingUrl、failureUrl 進(jìn)行  permitAll 設(shè)置(如果用戶配置了 permitAll 的話)。

  4. registerDefaultAuthenticationEntryPoint 則是注冊(cè)異常的處理器。

再來(lái)看 configure  方法:

@Override public void configure(B http) throws Exception {  PortMapper portMapper = http.getSharedObject(PortMapper.class);  if (portMapper != null) {   authenticationEntryPoint.setPortMapper(portMapper);  }  RequestCache requestCache = http.getSharedObject(RequestCache.class);  if (requestCache != null) {   this.defaultSuccessHandler.setRequestCache(requestCache);  }  authFilter.setAuthenticationManager(http    .getSharedObject(AuthenticationManager.class));  authFilter.setAuthenticationSuccessHandler(successHandler);  authFilter.setAuthenticationFailureHandler(failureHandler);  if (authenticationDetailsSource != null) {   authFilter.setAuthenticationDetailsSource(authenticationDetailsSource);  }  SessionAuthenticationStrategy sessionAuthenticationStrategy = http    .getSharedObject(SessionAuthenticationStrategy.class);  if (sessionAuthenticationStrategy != null) {   authFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);  }  RememberMeServices rememberMeServices = http    .getSharedObject(RememberMeServices.class);  if (rememberMeServices != null) {   authFilter.setRememberMeServices(rememberMeServices);  }  F filter = postProcess(authFilter);  http.addFilter(filter); }

configure  中的邏輯就很簡(jiǎn)答了,構(gòu)建各種各樣的回調(diào)函數(shù)設(shè)置給 authFilter,authFilter 再去 postProcess 中走一圈注冊(cè)到 Spring  容器中,最后再把 authFilter 添加到過(guò)濾器鏈中。

這便是 AbstractAuthenticationFilterConfigurer  的主要功能。需要提醒大家的是,我們?nèi)粘E渲玫模纾?/p>

  • loginPage

  • loginProcessingUrl

  • permitAll

  • defaultSuccessUrl

  • failureUrl

  • ...

等方法都是在這里定義的。

最后我們?cè)賮?lái)看看 FormLoginConfigurer。

2.2.3  FormLoginConfigurer

FormLoginConfigurer 在定義是,明確了  AbstractAuthenticationFilterConfigurer 中的泛型是  UsernamePasswordAuthenticationFilter,也就是我們這里最終要配置的過(guò)濾是  UsernamePasswordAuthenticationFilter。

FormLoginConfigurer 重寫了 init  方法,配置了一下默認(rèn)的登錄頁(yè)面。其他的基本上都是從父類來(lái)的,未做太多改變。

另外我們?nèi)粘E渲玫暮芏鄸|西也是來(lái)自這里:

怎么理解SecurityConfigurer

感謝各位的閱讀,以上就是“怎么理解SecurityConfigurer”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)怎么理解SecurityConfigurer這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI