关于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> | 
                    
                
                
            
        
浙公网安备 33010602011771号