在FilterChainProxy初始化的過程當中,大概描述了標籤解析的一些步驟,但不夠詳細
<http auto-config="true">
<remember-me key="workweb" token-validity-seconds="3600" data-source-ref="dataSource"/>
<form-login login-page="/login.jsp"/>
<logout logout-success-url="/login.jsp"/>
<intercept-url pattern="/*" access="ROLE_USER"/>
</http>web
http標籤的解析過程由類org.springframework.security.config.http.HttpSecurityBeanDefinitionParser解析。
public BeanDefinition parse(Element element, ParserContext pc) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element));
pc.pushContainingComponent(compositeDef);
final Object source = pc.extractSource(element);
//portMapperName、matcher主要提供給SSL相關類使用
final String portMapperName = createPortMapper(element, pc);
final UrlMatcher matcher = createUrlMatcher(element);
//http標籤構造器,該構造函數中對intercept-url、create-session子標籤
//進行了預處理,並將全部的intercept-url信息放到List中。
HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, pc, matcher, portMapperName);
//處理List中的intercept-url信息(如pattern、filters),並將結果放到
//Map集合filterChainMap中
httpBldr.parseInterceptUrlsForEmptyFilterChains();
//建立過濾器SecurityContextPersistenceFilter
httpBldr.createSecurityContextPersistenceFilter();
//建立過濾器SessionManagementFilter
httpBldr.createSessionManagementFilters();
//新建一個空的provider集合
ManagedList<BeanReference> authenticationProviders = new ManagedList<BeanReference>();
//經過空的provider集合產生一個ProviderManager的bean定義
BeanReference authenticationManager = createAuthenticationManager(element, pc, authenticationProviders, null);
//建立過濾器SecurityContextHolderAwareRequestFilter
httpBldr.createServletApiFilter();
//判斷intercept-url標籤是否有requires-channel屬性,若是有,則建立過濾器
//ChannelProcessingFilter
httpBldr.createChannelProcessingFilter();
//建立過濾器FilterSecurityInterceptor
//這個建立過程比較複雜,分別爲:
//1.須要判斷是否使用表達式use-expressions
//2.解析intercept-url中的access等屬性
//3.RoleVoter、AffirmativeBased的定義…………
httpBldr.createFilterSecurityInterceptor(authenticationManager);
//下面是與認證有關的過濾器,HttpConfigurationBuilder,
//AuthenticationConfigBuilder將解析的職責進行了分離
AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, pc,
httpBldr.isAllowSessionCreation(), portMapperName);
//建立過濾器AnonymousAuthenticationFilter,而且構造了provider:
//AnonymousAuthenticationProvider,供ProviderManager使用
authBldr.createAnonymousFilter();
//判斷是否有remember-me標籤,若是有,則建立過濾器
//RememberMeAuthenticationFilter,而且構造了provider:
//RememberMeAuthenticationProvider供ProviderManager使用
authBldr.createRememberMeFilter(authenticationManager);
//判斷是否有request-cache標籤,若是有,則構造ref指明的bean定義
//若是沒有,則構造HttpSessionRequestCache緩存
authBldr.createRequestCache();
//建立過濾器BasicAuthenticationFilter
authBldr.createBasicFilter(authenticationManager);
//建立LoginUrlAuthenticationEntryPoint,以及建立過濾器
//UsernamePasswordAuthenticationFilter
authBldr.createFormLoginFilter(httpBldr.getSessionStrategy(), authenticationManager);
//判斷是否使用了openid-login,若是有,則構造openId客戶端
//org.springframework.security.openid.OpenID4JavaConsumer
authBldr.createOpenIDLoginFilter(httpBldr.getSessionStrategy(), authenticationManager);
//判斷是否使用了x509,若是有,則建立過濾器
//X509AuthenticationFilter
authBldr.createX509Filter(authenticationManager);
//判斷是否配置了logout,若是有,則建立過濾器LogoutFilter
authBldr.createLogoutFilter();
//判斷是否配置login-page屬性,若是沒有,則建立過濾器
//DefaultLoginPageGeneratingFilter,生成默認登陸頁面
authBldr.createLoginPageFilterIfNeeded();
//建立UserDetailsServiceInjectionBeanPostProcessor
//動態向x50九、openID、rememberme服務注入UserDetailsService
//主要使用了spring的BeanPostProcessor接口功能
authBldr.createUserServiceInjector();
//建立過濾器ExceptionTranslationFilter
authBldr.createExceptionTranslationFilter();spring
List<OrderDecorator> unorderedFilterChain = new ArrayList<OrderDecorator>();
//向FilterChain鏈中添加filters
unorderedFilterChain.addAll(httpBldr.getFilters());
unorderedFilterChain.addAll(authBldr.getFilters());
//向ProviderManager中添加provider
authenticationProviders.addAll(authBldr.getProviders());express
BeanDefinition requestCacheAwareFilter = new RootBeanDefinition(RequestCacheAwareFilter.class);
requestCacheAwareFilter.getPropertyValues().addPropertyValue("requestCache", authBldr.getRequestCache());
unorderedFilterChain.add(new OrderDecorator(requestCacheAwareFilter, REQUEST_CACHE_FILTER));
//添加自定義的Filter,也就是custom-filter標籤訂義的Filter
unorderedFilterChain.addAll(buildCustomFilterList(element, pc));
//對FilterChian鏈中的Filter進行排序,排序規則參見SecurityFilters枚舉類
Collections.sort(unorderedFilterChain, new OrderComparator());
checkFilterChainOrder(unorderedFilterChain, pc, source);緩存
List<BeanMetadataElement> filterChain = new ManagedList<BeanMetadataElement>();session
for (OrderDecorator od : unorderedFilterChain) {
filterChain.add(od.bean);
}數據結構
ManagedMap<BeanDefinition, List<BeanMetadataElement>> filterChainMap = httpBldr.getFilterChainMap();
BeanDefinition universalMatch = new RootBeanDefinition(String.class);
universalMatch.getConstructorArgumentValues().addGenericArgumentValue(matcher.getUniversalMatchPattern());
filterChainMap.put(universalMatch, filterChain);
//構造FilterChainProxy的Bean
registerFilterChainProxy(pc, filterChainMap, matcher, source);app
pc.popAndRegisterContainingComponent();
return null;
}jsp
至此,大概http標籤的解析已經差很少了,雖然每一個Filter的BeanDefinition建立過程尚未一一細說,但基本步驟以下:
1.經過Filter的類路徑獲取BeanDefinitionBuilder對象,如
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(filterClassName);
2.解析xml標籤屬性,再經過BeanDefinitionBuilder的addPropertyValue、addPropertyReference等方法設置Filter對應BeanDefinition的屬性值、依賴bean
3.註冊BeanDefinition。經過
ParserContext.registerBeanComponent(
new BeanComponentDefinition(BeanDefinition,beanId));
完成bean的註冊。還能夠經過ParserContext.getRegistry().registerAlias
方法註冊bean的別名
實際上,標籤解析就是構造BeanDefinition,而後註冊到bean factory中。而BeanDefinition就是Spring中定義bean的數據結構。 ide