1. 前言
在上一篇我們對AuthenticationManager
的初始化的細節進行了分析,其中裡面有一段程式碼引起了不少同學的注意:
ApplicationContext context = http.getSharedObject(ApplicationContext.class);
CaptchaAuthenticationProvider captchaAuthenticationProvider = context.getBean("captchaAuthenticationProvider", CaptchaAuthenticationProvider.class);
上面直接從HttpSecurity
物件中獲取到Spring的應用上下文物件ApplicationContext
,它是怎麼做到的呢?SharedObject又是個什麼概念?今天就來搞清楚這個問題。
2. SharedObject
在Spring Security中SharedObject既不是物件也不是介面,而是某一類“可共享”的物件的統稱。
顧名思義,SharedObject的意思是可共享的物件。它的作用是如果一些物件你希望在不同的作用域配置中共享它們就把這些物件變成SharedObject,有點分散式物件的感覺。為了更加便於你理解,下面是相關的體系結構:
AbstractConfiguredSecurityBuilder
或者HttpSecurityBuilder
的實現類才具有操作SharedObject的能力。一種是註冊SharedObject,另一種是獲取SharedObject。
SharedObject的註冊
SharedObject會以其Class
型別為Key
,例項為Value
儲存到一個HashMap<Class<?>,Object>
中,具體可看HttpSecurity
原始碼。它的註冊分為兩個部分,第一是HttpSecurity
初始化的時候裝配進去的。我們來看看:
我們熟知的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. 總結
SharedObject是Spring Security提供的一個非常好用的功能,如果你在不同的地方需要對一個物件重複使用就可以將它註冊為SharedObject,甚至直接注入Spring IoC像開頭那樣獲取就可以了。這個特效能夠簡化配置,提高程式碼的可讀性,也為Spring Security的DSL特性打下了基礎。好了今天的分享就到這裡,我是:碼農小胖哥,多多關注,獲取更多實用的程式設計乾貨。
關注公眾號:Felordcn 獲取更多資訊