最近在折腾shiro的时候,自己挖了坑,并跳了进去. 问题解决后. 本人觉得还是有必要将问题记录下来,以免以后挖坑.
<bean id="logout" class="org.apache.shiro.web.filter.authc.LogoutFilter">
<property name="redirectUrl" value=""/>
</bean>
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value=""/>
<property name="successUrl" value=""/>
<property name="filters">
<util:map>
<entry key="oauth2Authc" value-ref="oAuth2AuthenticationFilter"/>
<entry key="sysUser" value-ref="sysUserFilter"/>
<entry key="logout" value-ref="logout"/>//这个地方要注意了
</util:map>
</property>
<property name="filterChainDefinitions">
<value>
/oauth2Failure.jsp = anon
/oauth2-login = oauth2Authc
/logout = logout
/** = sysUser
</value>
</property>
</bean>
org.apache.shiro.web.filter.authc.LogoutFilter logout = ApplicationContext.getBean(LogoutFilter.class);
大家可以猜猜看通过ShiroFilterFactoryBean获取的logoutFilter Bean与Spring获取的logoutFilter Bean是同一个对象么. 答案是: NO
注意蓝色的部分,如果在项目中,显示定义了LogoutFilter过滤器,必须要在ShiroFilterFactoryBean显示添加进去.否则你项目的logoutFilter就不是单例在运行了.
为啥我会这样说呢,不着急,我们来看看shiro源码就一目了然.
//ShiroFilterFactoryBean 中方法
protected FilterChainManager createFilterChainManager() {
DefaultFilterChainManager manager = new DefaultFilterChainManager();
Map<String, Filter> defaultFilters = manager.getFilters();//获取shiro默认的filters链
//apply global settings if necessary:
for (Filter filter : defaultFilters.values()) {
applyGlobalPropertiesIfNecessary(filter);
}
//Apply the acquired and/or configured filters:
Map<String, Filter> filters = getFilters();//在外部使用使用filters注入自定义filter
if (!CollectionUtils.isEmpty(filters)) {
for (Map.Entry<String, Filter> entry : filters.entrySet()) {
String name = entry.getKey();
Filter filter = entry.getValue();
applyGlobalPropertiesIfNecessary(filter);
if (filter instanceof Nameable) {
((Nameable) filter).setName(name);
}
//'init' argument is false, since Spring-configured filters should be initialized
//in Spring (i.e. 'init-method=blah') or implement InitializingBean:
manager.addFilter(name, filter, false); //添加到默认的filters链里面
}
}
//build up the chains:
Map<String, String> chains = getFilterChainDefinitionMap();
if (!CollectionUtils.isEmpty(chains)) {
for (Map.Entry<String, String> entry : chains.entrySet()) {
String url = entry.getKey();
String chainDefinition = entry.getValue();
manager.createChain(url, chainDefinition);
}
}
return manager;
}
大家注意下蓝色的部分,他的作用就是讲已经定义的filter添加filters链里面. 第一次添加已经默认的logoutFilter添加了,第二次添加会将spring定义的logout再次添加进行覆盖.
因为spring获取logoutfilter Bean,是通过ApplicationContext来获取的. shiroFactory获取logoutfilter Bean,是通过DefaultFilterChainManager来获取的.
所以不管你使用spring获取logoutfilter Bean,还是使用shiroFactory获取logoutfilter Bean,他们都是同一个对象.这样就保证对象是单例.