關於spring security自定義sessionRegistry不工做的緣由簡析

最近調了一下spring security的集羣session共享,用到了自定義的SessionRegistry,卻發現怎麼也不工做,翻了翻stackoverfllow,也沒找到靠譜的辦法,最後本身debug,找到了問題所在java

本文基於 Spring3.1.5,Spring security 2.0.4web

最開始配置以下:spring

<beans:bean id="sessionRegistry"
     class="com.shop.core.security.support.SessionRegistryImpl" scope="singleton">
   <beans:property name="cacheManager" ref="cacheManager" />
</beans:bean>
<bean:http auto-config="false" entry-point-ref="loginUrlEntryPoint">
...
<bean:concurrent-session-control max-sessions="200000"
   exception-if-maximum-exceeded="false" expired-url="/outline.htm"
   session-registry-alias="sessionRegistry"  />
...
</bean:http>


debug發現自定義的SessionRegistryImpl類也有載入,可是最終系統調用的仍然是原來的session

org.springframework.security.concurrent.SessionRegistryImpl

經過閱讀源代碼發現了其中緣由,解釋見註釋:
ide

public class ConcurrentSessionsBeanDefinitionParser implements BeanDefinitionParser {

    static final String ATT_EXPIRY_URL = "expired-url";
    static final String ATT_MAX_SESSIONS = "max-sessions";
    static final String ATT_EXCEPTION_IF_MAX_EXCEEDED = "exception-if-maximum-exceeded";
    static final String ATT_SESSION_REGISTRY_ALIAS = "session-registry-alias";
    static final String ATT_SESSION_REGISTRY_REF = "session-registry-ref";
   
    public BeanDefinition parse(Element element, ParserContext parserContext) {
       CompositeComponentDefinition compositeDef =
         new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
      parserContext.pushContainingComponent(compositeDef);
       
       BeanDefinitionRegistry beanRegistry = parserContext.getRegistry();
//這裏經過session-registry-ref 去獲取自定義的sessionregistry,
        String sessionRegistryId = element.getAttribute(ATT_SESSION_REGISTRY_REF);
        
        if (!StringUtils.hasText(sessionRegistryId)) {         
            RootBeanDefinition sessionRegistry = new RootBeanDefinition(SessionRegistryImpl.class);        
            beanRegistry.registerBeanDefinition(BeanIds.SESSION_REGISTRY, sessionRegistry);
            parserContext.registerComponent(new BeanComponentDefinition(sessionRegistry, BeanIds.SESSION_REGISTRY));
            sessionRegistryId = BeanIds.SESSION_REGISTRY;
        } else {
        //註冊默認ID
           // Register the default ID as an alias so that things like session fixation filter can access it
           beanRegistry.registerAlias(sessionRegistryId, BeanIds.SESSION_REGISTRY);
        }

        String registryAlias = element.getAttribute(ATT_SESSION_REGISTRY_ALIAS);
        if (StringUtils.hasText(registryAlias)) {
           beanRegistry.registerAlias(sessionRegistryId, registryAlias);
        }      

        BeanDefinitionBuilder filterBuilder =
                BeanDefinitionBuilder.rootBeanDefinition(ConcurrentSessionFilter.class);
        filterBuilder.addPropertyValue("sessionRegistry", new RuntimeBeanReference(sessionRegistryId));

也便是說sessionRegistry在作初始化的時候,spring security用了beanRegistry去管理了自身默認的bean的實現,若是你要使用自定義的,就須要給出相應的配置以取代默認,在BeanIds抽象類裏面定義了默認的實現別名,若是獲取不到就去獲取默認。ui

public abstract class BeanIds {

    /** External alias for FilterChainProxy bean, for use in web.xml files */
    public static final String SPRING_SECURITY_FILTER_CHAIN = "springSecurityFilterChain";  

    /** Package protected as end users shouldn't really be using this BFPP directly */
   static final String INTERCEPT_METHODS_BEAN_FACTORY_POST_PROCESSOR = "_interceptMethodsBeanfactoryPP";
    static final String CONTEXT_SOURCE_SETTING_POST_PROCESSOR = "_contextSettingPostProcessor";
    static final String ENTRY_POINT_INJECTION_POST_PROCESSOR = "_entryPointInjectionBeanPostProcessor";
    static final String USER_DETAILS_SERVICE_INJECTION_POST_PROCESSOR = "_userServiceInjectionPostProcessor";
    static final String SESSION_REGISTRY_INJECTION_POST_PROCESSOR = "_sessionRegistryInjectionPostProcessor";    
    static final String FILTER_CHAIN_POST_PROCESSOR = "_filterChainProxyPostProcessor";
    static final String FILTER_LIST = "_filterChainList";

    public static final String JDBC_USER_DETAILS_MANAGER = "_jdbcUserDetailsManager";
   public static final String USER_DETAILS_SERVICE = "_userDetailsService";
   public static final String ANONYMOUS_PROCESSING_FILTER = "_anonymousProcessingFilter";
   public static final String ANONYMOUS_AUTHENTICATION_PROVIDER = "_anonymousAuthenticationProvider";
   public static final String BASIC_AUTHENTICATION_FILTER = "_basicAuthenticationFilter";
   public static final String BASIC_AUTHENTICATION_ENTRY_POINT = "_basicAuthenticationEntryPoint";
   public static final String SESSION_REGISTRY = "_sessionRegistry";
   public static final String CONCURRENT_SESSION_FILTER = "_concurrentSessionFilter";
   因此個人配置裏面只須要加上session-registry-ref就行了。。
   <beans:bean id="sessionRegistry"
     class="com.shop.core.security.support.SessionRegistryImpl" scope="singleton">
   <beans:property name="cacheManager" ref="cacheManager" />
</beans:bean>
<bean:http auto-config="false" entry-point-ref="loginUrlEntryPoint">
...
<bean:concurrent-session-control max-sessions="200000"
   exception-if-maximum-exceeded="false" expired-url="/outline.htm"
   session-registry-alias="sessionRegistry"  session-registry-ref="sessionRegistry"/>
...
</bean:http>
相關文章
相關標籤/搜索