最近調了一下spring security的集羣session共享,用到了自定義的SessionRegistry,卻發現怎麼也不工做,翻了翻stackoverfllow,也沒找到靠譜的辦法,最後本身debug,找到了問題所在java
本文基於 Spring3.1.5,Spring security 2.0.4node
最開始配置以下:web
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類也有載入,可是最終系統調用的仍然是原來的spring
org.springframework.security.concurrent.SessionRegistryImpl
經過閱讀源代碼發現了其中緣由,解釋見註釋:session
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抽象類裏面定義了默認的實現別名,若是獲取不到就去獲取默認。ide
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>
|