Spring Security 實戰干貨:分布式對象SharedObject


1. 前言

上一篇我們對AuthenticationManager的初始化的細節進行了分析,其中里面有一段代碼引起了不少同學的注意:

  ApplicationContext context = http.getSharedObject(ApplicationContext.class);
    CaptchaAuthenticationProvider captchaAuthenticationProvider = context.getBean("captchaAuthenticationProvider", CaptchaAuthenticationProvider.class);

上面直接從HttpSecurity對象中獲取到Spring的應用上下文對象ApplicationContext,它是怎么做到的呢?SharedObject又是個什么概念?今天就來搞清楚這個問題。

2. SharedObject

Spring SecuritySharedObject既不是對象也不是接口,而是某一類“可共享”的對象的統稱。

顧名思義,SharedObject的意思是可共享的對象。它的作用是如果一些對象你希望在不同的作用域配置中共享它們就把這些對象變成SharedObject,有點分布式對象的感覺。為了更加便於你理解,下面是相關的體系結構:

配置類的組織架構

AbstractConfiguredSecurityBuilder或者HttpSecurityBuilder的實現類才具有操作SharedObject的能力。一種是注冊SharedObject,另一種是獲取SharedObject

SharedObject的注冊

SharedObject會以其Class類型為Key,實例為Value存儲到一個HashMap<Class<?>,Object>中,具體可看HttpSecurity源碼。它的注冊分為兩個部分,第一是HttpSecurity初始化的時候裝配進去的。我們來看看:

注入AuthenticationManagerBuilder

我們熟知的AuthenticationManagerBuilder在這里被共享。

還有一部分是在所有的HttpSecurityBuilder對象初始化時注冊的。它初始化和配置都是由SecurityConfigurer來完成的:

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

上面兩個方法分別用來初始化和配置HttpSecurityBuilder。比如我們熟知的WebSecurityConfigurerAdapter就是用來配置HttpSecurity的,在其init方法中我們可以找到相關的代碼:

private Map<Class<?>, Object> createSharedObjects() {
   Map<Class<?>, Object> sharedObjects = new HashMap<>();
   sharedObjects.putAll(localConfigureAuthenticationBldr.getSharedObjects());
   sharedObjects.put(UserDetailsService.class, userDetailsService());
   sharedObjects.put(ApplicationContext.class, context);
   sharedObjects.put(ContentNegotiationStrategy.class, contentNegotiationStrategy);
   sharedObjects.put(AuthenticationTrustResolver.class, trustResolver);
   return sharedObjects;
}

這也是我在文章開頭可以獲取到ApplicationContext的根本原因。

SharedObject的獲取和使用

我們能獲取到哪些被標記為SharedObject類呢?SecurityConfigurer有很多實現,這些實現都是用來配置一些特定的同認證授權相關的功能的。比如OAuth2ClientConfigurer用來配置OAuth2客戶端的,它里面就將常用的一些對象設置為SharedObject

public OAuth2ClientConfigurer<B> clientRegistrationRepository(ClientRegistrationRepository clientRegistrationRepository) {
   Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null");
   this.getBuilder().setSharedObject(ClientRegistrationRepository.class, clientRegistrationRepository);
   return this;
}

當你在HttpSecurity的配置中的其它地方需要用到ClientRegistrationRepository時,你可以直接通過getSharedObject獲取,就像文章開頭一樣,而不用在去寫一些獲取方法了。

3. 總結

SharedObjectSpring Security提供的一個非常好用的功能,如果你在不同的地方需要對一個對象重復使用就可以將它注冊為SharedObject,甚至直接注入Spring IoC像開頭那樣獲取就可以了。這個特性能夠簡化配置,提高代碼的可讀性,也為Spring SecurityDSL特性打下了基礎。好了今天的分享就到這里,我是:碼農小胖哥,多多關注,獲取更多實用的編程干貨。

關注公眾號:Felordcn 獲取更多資訊

個人博客:https://felord.cn


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM