Shrio源码分析---ShiroFilterFactoryBean

在Spring MVC集成Shiro中,最重要的当属这个ShiroFactoryBean了,可以说是开放给开发者的一个入口。通常的开发配置如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
	 http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <!-- 配置shrio的验证管理 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realms">
            <list>
                <ref bean="shiroRealm"/>
            </list>
        </property>
    </bean>

    <!-- 配置shrio的验证 -->
    <bean id="shiroRealm" class="com.gameloft9.demo.security.ShiroRealm"/>

    <!-- 配置shrio的过滤功能 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- shiro的核心安全接口 -->
        <property name="securityManager" ref="securityManager"/>
        <!-- 要求登录时的链接 -->
        <property name="loginUrl" value="/login"/>
        <!-- 未授权的链接 -->
        <property name="unauthorizedUrl" value="/views/unaouth.jsp"/>
        <!-- 过滤器 -->
        <property name="filters">
            <map>
                <entry key="authc">
                    <bean class="com.gameloft9.demo.shiro.ShiroAuthFilter"/>
                </entry>
            </map>
        </property>
        <!-- shiro连接约束配置 -->
        <property name="filterChainDefinitions">
            <value>
                /ImgValidateServlet = anon
                /queryPublishContent.do=anon
                /login = anon
                /*.do = authc
                / = anon
            </value>
        </property>
    </bean>
</beans>

嗯,很常见的配置三部曲,配置SecurityManager,配置Realm,然后配置过滤器和过滤链。让我们对比着看看ShiroFilterFactoryBean的内容:

    private SecurityManager securityManager;
    private Map<String, Filter> filters = new LinkedHashMap();
    private Map<String, String> filterChainDefinitionMap = new LinkedHashMap();
    private String loginUrl;
    private String successUrl;
    private String unauthorizedUrl;
    private AbstractShiroFilter instance;

       可以看到,xml配置大部分就是在设置这些属性内容,除了最后的那个instance,这个后面再说。在上面的过滤链设置中,我们使用了anon,authc等filter,但是xml配置中我们过滤器只设置了authc。那么其它的过滤器是哪里来的,为什么可以直接使用?

       其实Shiro已经内置了一些常用的过滤器,例如:anon,roles,user等等。这些过滤器被定义在一个默认的过滤器枚举里面,如下所示:

package org.apache.shiro.web.filter.mgt;

import org.apache.shiro.util.ClassUtils;
import org.apache.shiro.web.filter.authc.*;
import org.apache.shiro.web.filter.authz.*;
import org.apache.shiro.web.filter.session.NoSessionCreationFilter;

import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import java.util.LinkedHashMap;
import java.util.Map;

public enum DefaultFilter {

    anon(AnonymousFilter.class),
    authc(FormAuthenticationFilter.class),
    authcBasic(BasicHttpAuthenticationFilter.class),
    logout(LogoutFilter.class),
    noSessionCreation(NoSessionCreationFilter.class),
    perms(PermissionsAuthorizationFilter.class),
    port(PortFilter.class),
    rest(HttpMethodPermissionFilter.class),
    roles(RolesAuthorizationFilter.class),
    ssl(SslFilter.class),
    user(UserFilter.class);

    private final Class<? extends Filter> filterClass;

    private DefaultFilter(Class<? extends Filter> filterClass) {
        this.filterClass = filterClass;
    }

    public Filter newInstance() {
        return (Filter) ClassUtils.newInstance(this.filterClass);
    }

    public Class<? extends Filter> getFilterClass() {
        return this.filterClass;
    }

}

这些默认的过滤器和用户自定义的过滤器组成了最终的过滤器集合,而它们添加的时机也不一样。在创建ShrioFilterFactoryBean的时候,用户自定义的filter已经被设置到了filters属性里面。这个filtes存放的只有用户添加的,不包含默认的。ShrioFilterFactoryBean创建AbstractShrioFilter实例的时候(也就是我们之前说的那个instance),会创建一个FilterChainManager。如下所示:

 protected AbstractShiroFilter createInstance() throws Exception {
        log.debug("Creating Shiro Filter instance.");
        SecurityManager securityManager = this.getSecurityManager();
        String msg;
        if(securityManager == null) {
            msg = "SecurityManager property must be set.";
            throw new BeanInitializationException(msg);
        } else if(!(securityManager instanceof WebSecurityManager)) {
            msg = "The security manager does not implement the WebSecurityManager interface.";
            throw new BeanInitializationException(msg);
        } else {
            FilterChainManager manager = this.createFilterChainManager();
            PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
            chainResolver.setFilterChainManager(manager);
            return new ShiroFilterFactoryBean.SpringShiroFilter((WebSecurityManager)securityManager, chainResolver);
        }
    }

       createFilterChainManager()方法里面会调用DefaultFilterChainManager manager = new DefaultFilterChainManager();创建一个默认的实例。现在魔法发生了,在构造函数里面,我们看到了addDefaultFilters方法!没错!这里就是添加默认filters的地方。更里面的内容,大家可以自己看看源码。

public DefaultFilterChainManager() {
        this.filters = new LinkedHashMap<String, Filter>();
        this.filterChains = new LinkedHashMap<String, NamedFilterList>();
        addDefaultFilters(false);
    }

       然后我们回到createFilterChainManager()方法里面来,创建了默认的filters后,会再去ShrioFilterFactoryBean拿到我们之前自定义好的filter,通过一个for循环把它们一个一个加进去,而且在manager.addFilter里面会覆盖重名的filter。也就是说用户自定义的filter会覆盖掉同名的默认的filter。

 protected FilterChainManager createFilterChainManager() {
        DefaultFilterChainManager manager = new DefaultFilterChainManager();
        Map<String, Filter> defaultFilters = manager.getFilters();
        Iterator var3 = defaultFilters.values().iterator();

        while(var3.hasNext()) {
            Filter filter = (Filter)var3.next();
            this.applyGlobalPropertiesIfNecessary(filter);
        }

        Map<String, Filter> filters = this.getFilters();
        String name;
        Filter filter;
        if(!CollectionUtils.isEmpty(filters)) {
            for(Iterator var10 = filters.entrySet().iterator(); var10.hasNext(); manager.addFilter(name, filter, false)) {
                Entry<String, Filter> entry = (Entry)var10.next();
                name = (String)entry.getKey();
                filter = (Filter)entry.getValue();
                this.applyGlobalPropertiesIfNecessary(filter);
                if(filter instanceof Nameable) {
                    ((Nameable)filter).setName(name);
                }
            }
        }

        Map<String, String> chains = this.getFilterChainDefinitionMap();
        if(!CollectionUtils.isEmpty(chains)) {
            Iterator var12 = chains.entrySet().iterator();

            while(var12.hasNext()) {
                Entry<String, String> entry = (Entry)var12.next();
                String url = (String)entry.getKey();
                String chainDefinition = (String)entry.getValue();
                manager.createChain(url, chainDefinition);
            }
        }

        return manager;
    }

      在方法的最后,还添加了我们xml设置的过滤链。这样我们xml配置里面的过滤器和过滤链就完整的被消化到了DefaultFilterChainManager里面去了,然后manager又被托管到PathMatchingFilterChainResolver(其实就是再加了一个正则匹配器)。最后返回了一个spring包装过的ShiroFilter(就是那个instance):

 FilterChainManager manager = this.createFilterChainManager();
 PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
 chainResolver.setFilterChainManager(manager);
 return new ShiroFilterFactoryBean.SpringShiroFilter((WebSecurityManager)securityManager, chainResolver);

核心内容就是我们的securityManager和FilterChainResolver,至此ShiroFilterFactoryBean的工作就做完了!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值