關於spring security自定義sessionRegistry


最近調了一下spring security的集群session共享,用到了自定義的SessionRegistry,卻發現怎么也不工作,翻了翻stackoverfllow,也沒找到靠譜的辦法,最后自己debug,找到了問題所在

本文基於 Spring3.1.5,Spring security 2.0.4

最開始配置如下:

1
2
3
4
5
6
7
8
9
10
11
< 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類也有載入,但是最終系統調用的仍然是原來的

org.springframework.security.concurrent.SessionRegistryImpl

通過閱讀源代碼發現了其中原因,解釋見注釋:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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的實現,java培訓時學到的東西。如果你要使用自定義的,就需要給出相應的配置以取代默認,在BeanIds抽象類里面定義了默認的實現別名,如果獲取不到就去獲取默認。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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>


免責聲明!

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



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