Shiro源码分析之ShiroFilterFactoryBean
博客专区 > 0909 的博客 > 博客详情
Shiro源码分析之ShiroFilterFactoryBean
0909 发表于1年前
Shiro源码分析之ShiroFilterFactoryBean
  • 发表于 1年前
  • 阅读 200
  • 收藏 7
  • 点赞 1
  • 评论 0

腾讯云实验室 1小时搭建人工智能应用,让技术更容易入门 免费体验 >>>   

摘要: 在web项目结合Spring DelegatingFilterProxy 使用安全框架Shiro,其最终是通过shiro-spring.jar中的ShiroFilterFactoryBean类来实现授权、资源管理、角色管理等功能。而这一切的安全管理实际上又是通Filter来实现的。

一、Spring 的DelegatingFilterProxy如何发现 Shiro 的ShiroFilterFactoryBean

简单的回顾一下,web.xml配置中的Spring DelegatingFilterProxy 的这个Filter是如何找到WebApplicationcontext 配置(Spring.xml配置文件)中的ShiroFilterFactoryBean。

web.xml配置:

<filter>
        <filter-name>securityFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
</filter>

其实际是通过上面web.xml文件中的securityFilter,securityFilter去找到spring-context.xml配置文件中类型为Filter,id为securityFilter的Bean。

spring-context.xml配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    <!-- 此处省略部分配置-->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<!-- 此处省略部分配置-->
		<property name="securityManager" ref="securityManager" />
		<property name="unauthorizedUrl" value="/" />
		<property name="filters">
			<map>
				<entry key="formAuthc" value-ref="formAuthc" />
			</map>
		</property>
		<property name="filterChainDefinitions">
			<value>
				/static/** = anon
				/login = formAuthc
				/logout = logout
			</value>
		</property>
	</bean>
</beans>

详解的源码分析可见http://my.oschina.net/u/1421030/blog/729706

二、Shiro 的ShiroFilterFactoryBean源码分析

前一节说到Spring的DelegatingFilterProxy是通过在Spring的配置文件中找到类型为Filter且id与web.xml文件其filter-name一致的Bean来发现ShiroFilterFactoryBean的。 但我们会发现ShiroFilterFactoryBean好像没有实现Filter接口,是不是有什么问题呢??

ShiroFilterFactoryBean 声明代码:

public class ShiroFilterFactoryBean implements FactoryBean, BeanPostProcessor... 

其实ShiroFilterFactoryBean 实现了FactoryBean接口正式在这里有我们想要的。 ApplicationContext的对待FactoryBean类型的Bean,通过配置文件的中Bean的id得到的其实是FactoryBean#getObject方法对应类型的Bean详细可见http://my.oschina.net/u/1421030/blog/729908。 现在来看看ShiroFilterFactoryBean 的getObject方法的具体实现吧。

ShiroFilterFactoryBean #getObject代码:

public Object getObject() throws Exception {
        if (instance == null) {
            instance = createInstance();
        }
        return instance;
    }

再看看

ShiroFilterFactoryBean #createInstance代码:

protected AbstractShiroFilter createInstance() throws Exception {
        logdebug("Creating Shiro Filter instance.");
        SecurityManager securityManager = getSecurityManager();
        //省略部分代码
        //创建FilterChain管理器,会将Shiro默认的Filter加入进来,同时将配置文件中的Filter加进来
        FilterChainManager manager = createFilterChainManager();
        PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
        chainResolver.setFilterChainManager(manager);
        return new SpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
    }

可以看到createInstance方法返回的是一个AbstractShiroFilter 类对象,而该类的父类实际实现了Filter接口。 再来看看createInstance方法中最重要的createFilterChainManager

ShiroFilterFactoryBean #createFilterChainManager代码:

  protected FilterChainManager createFilterChainManager() {
        /*创建默认的FilterChainManager,创建时会将anon, authc, authcBasic等Filter加入*/
        DefaultFilterChainManager manager = new DefaultFilterChainManager();
        Map<String, Filter> defaultFilters = manager.getFilters();
        //apply global settings if necessary:
        for (Filter filter : defaultFilters.values()) {
            applyGlobalPropertiesIfNecessary(filter);
        }
       //得到Spring配置文件中设置给ShiroFilterFactoryBean 的Filter
        Map<String, Filter> filters = getFilters();
        /*省略部分代码,此处将Spring设置给ShiroFilterFactoryBean 的Filter
         加入DefaultFilterChainManager 
        */
        /*得到配置文件中ShiroFilterFactoryBean 对应的filterChainDefinitions属性设置的键值对
         最终能根据vaule找到其对应的其实类Filter的全名与对应的FilterConfig信息
        */
        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;
    }

先看看 DefaultFilterChainManager manager = new DefaultFilterChainManager()

DefaultFilterChainManager构造函数代码

 public DefaultFilterChainManager() {
        this.filters = new LinkedHashMap<String, Filter>();
        this.filterChains = new LinkedHashMap<String, NamedFilterList>();
       //加入Shiro中默认的Filter
       addDefaultFilters(false);
    }

DefaultFilterChainManager#addDefaultFilters代码

protected void addDefaultFilters(boolean init) {
        for (DefaultFilter defaultFilter : DefaultFilter.values()) {
            addFilter(defaultFilter.name(), defaultFilter.newInstance(), init, false);
        }
    }

DefaultFilter代码

public enum DefaultFilter {
    anon(AnonymousFilter.class),
    authc(FormAuthenticationFilter.class),
    authcBasic(BasicHttpAuthenticationFilter.class),
    logout(LogoutFilter.class),
    //省略部分代码
}

到这里终于看到了为什么我们可在spring-context.xml中的ShiroFilterFactoryBean定义中使用anon, authc,authcBasic等去设置filterChainDefinitions啦。 spring-context.xml配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    <!-- 此处省略部分配置-->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<!-- 此处省略部分配置-->
		<property name="securityManager" ref="securityManager" />
		<property name="unauthorizedUrl" value="/" />
		<property name="filters">
			<map>
				<entry key="formAuthc" value-ref="formAuthc" />
			</map>
		</property>
		<property name="filterChainDefinitions">
			<value>
				/static/** = anon
				/login = formAuthc
				/logout = logout
			</value>
		</property>
	</bean>
</beans>

下面一些过程后面的文章分析。

共有 人打赏支持
粉丝 17
博文 15
码字总数 23892
×
0909
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: