Fork me on GitHub
07 May 2018

在Spring MVC中,DelegatingFilterProxy会代理Spring上下文中实现Servlet Filter接口的类,该类负责控制调用项目中的Servlet Filter类,包括Shiro Filter。下面我们来看看具体流程和实现。

目录

1. DelegatingFilterProxy

DelegatingFilterProxy会在上下文中寻找名为targetBeanName(web.xml中配置)的值的bean,并代理该实例。

DelegatingFilterProxy

// 创建delegate
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
	Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
	if (isTargetFilterLifecycle()) {
		delegate.init(getFilterConfig());
	}
	return delegate;
}

流程图:

请求请求TomcatTomcatweb.xmlweb.xmlDelegatingFilterProxyDelegatingFilterProxyShiroFilterFactoryBeanShiroFilterFactoryBeanShiroFilterShiroFilterdoFilterinitDelegategetObjectinvokeDelegatedoFilter

2. Shiro处理流程

ShiroFilterFactoryBean,负责创建和维护ShiroFilter实例,实现了Spring的BeanPostProcessor和FactoryBean,通过postProcessBeforeInitialization方法来缓存上下文中存在的filter,另外管理以下配置:

  • securityManager:安全管理器
  • loginUrl:登陆路径
  • successUrl:登陆成功跳转路径
  • unauthorizedUrl:未授权路径
  • filterChainDefinitions:过滤器和路径规则映射关系

ShiroFilterFactoryBean

// 创建FilterChainManager实例
protected FilterChainManager createFilterChainManager() {

    DefaultFilterChainManager manager = new DefaultFilterChainManager();
    Map<String, Filter> defaultFilters = manager.getFilters();

    // 配置全局默认提供的filter
    // org.apache.shiro.web.filter.mgt.DefaultFilter,定义了默认实现的filter
    //
    // 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);
    for (Filter filter : defaultFilters.values()) {
        applyGlobalPropertiesIfNecessary(filter);
    }

    // 配置filters属性中定义的filter
    Map<String, Filter> filters = getFilters();
    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);
            }

            manager.addFilter(name, filter, false);
        }
    }

    // 创建filter链,需定义filterChainDefinitions
    // 解析filterChainDefinitions,确立路由规则和定义的filter别名关系,并创建filter链
    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;
}
/**
 *  创建AbstractShiroFilter实例,该类实现了Filter接口
 *  确保securityManager为WebSecurityManager
 *  根据缓存的filters创建FilterChainManager和PathMatchingFilterChainResolver
 */
protected AbstractShiroFilter createInstance() throws Exception {
    // 检查参数
    log.debug("Creating Shiro Filter instance.");

    SecurityManager securityManager = getSecurityManager();
    if (securityManager == null) {
        String msg = "SecurityManager property must be set.";
        throw new BeanInitializationException(msg);
    }

    if (!(securityManager instanceof WebSecurityManager)) {
        String msg = "The security manager does not implement the WebSecurityManager interface.";
        throw new BeanInitializationException(msg);
    }

    // 管理路由规则和filter的映射关系
    FilterChainManager manager = createFilterChainManager();

    // 匹配路由规则(Ant-style),并调用FilterChainManager做相应的操作
    PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
    chainResolver.setFilterChainManager(manager);

    // SpringShiroFilter包装securityManager,chainResolver,便于调用
    return new SpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
}

Shiro执行过程:

ShiroFilterShiroFilterSubjectSubjectWebSecurityManagerWebSecurityManagerAuthorizingRealmAuthorizingRealmCredentialsMatcherCredentialsMatcherloginedloginlogindoGetAuthenticationInfodoCredentialsMatchstore user message

有关登陆过程的详细代码分析可阅读之前的文章 Shiro 登陆原理解析以及配置多个Realm了解更多。

通过以上分析我们可得知,filter和路由规则是实现权限管理等功能的必要条件,Shiro通过一系列的路由匹配,找到合适的Filter,从而执行对应的拦截逻辑处理。如果默认(DefaultFilter)定义的规则不满足于需求,可添加自定义filter,并配置对应的路由规则即可。

现在看来Shiro是不是很简单而且易用,👍。