ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Shiro流程简析 过滤器

2021-11-23 23:34:47  阅读:432  来源: 互联网

标签:beanName request Bean 简析 过滤器 2.2 null Shiro


简介

本文简单分析Spring Shiro框架中过滤器的使用,涉及过滤器的配置、初始化过程、过滤流程;

配置

Shiro中对过滤器的配置,核心是对ShiroFilterFactoryBean的配置,主要分为三部分:

  1. 配置SecurityManager;
  2. 配置过滤器;
  3. 配置请求URL过滤规则;

常见的配置代码如下:

@Bean("shiroFilterFactoryBean")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

    // 设置SecurityManager
    shiroFilterFactoryBean.setSecurityManager(securityManager);

    // 自定义过滤规则
    Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
    filterChainDefinitionMap.put("/**", "authc");
    shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

    // 自定义过滤器
    LinkedHashMap<String, Filter> filterMap = new LinkedHashMap<>();
    filterMap.put("authc", new ShiroFormAuthenticationFilter());
    shiroFilterFactoryBean.setFilters(filterMap);

    return shiroFilterFactoryBean;
}

配置SecurityManager

ShiroFilterFactoryBean需要注入SecurityManager实例,且要求为WebSecurityManager类型;ShiroFilterFactoryBean在创建AbstractShiroFilter时,会先校验SecurityManager实例;

配置过滤器

可以自定义过滤器实现,并设置该过滤器实现的名称;设置的名称和Shiro框架默认提供的过滤器的名称:

  • 相同,则覆盖Shiro框架默认提供的过滤器;
  • 不同,则添加该过滤器到Shiro框架的过滤器集合;

DefaultFilter定义了Shiro框架默认提供的过滤器和名称的对应关系,如下:

anon(AnonymousFilter.class),
authc(FormAuthenticationFilter.class),
authcBasic(BasicHttpAuthenticationFilter.class),
authcBearer(BearerHttpAuthenticationFilter.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),
invalidRequest(InvalidRequestFilter.class);

配置请求URL过滤规则

配置请求URL需要被哪些过滤器处理,可以使用Shiro框架默认提供的过滤器,也可以使用自定义过滤器实现,前提是自定义过滤器实现已经加入到Shiro框架的过滤器集合中;

请求URL支持通配符;

初始化

本文主要分析Shiro框架中核心过滤器ShiroFilterFactoryBean的初始化过程,ShiroFilterFactoryBean是个BeanFactory,用于构建AbstractShiroFilter Bean,所以本质是初始化ShiroFilterFactoryBean.SpringShiroFilter;

入口为:ServletContextInitializerBeans的getOrderedBeansOfType(ListableBeanFactory beanFactory, Class<T> type, Set<?> excludes);type为interface javax.servlet.Filter;

private <T> List<Entry<String, T>> getOrderedBeansOfType(
			ListableBeanFactory beanFactory, Class<T> type, Set<?> excludes) {
		Comparator<Entry<String, T>> comparator = (o1,
				o2) -> AnnotationAwareOrderComparator.INSTANCE.compare(o1.getValue(),
						o2.getValue());
        // 获取javax.servlet.Filter类型beanName列表,其中包括"shiroFilterFactoryBean"
		String[] names = beanFactory.getBeanNamesForType(type, true, false);
		Map<String, T> map = new LinkedHashMap<>();
		for (String name : names) {
			if (!excludes.contains(name) && !ScopedProxyUtils.isScopedTarget(name)) {
                // 根据"shiroFilterFactoryBean"获取Filter Bean
				T bean = beanFactory.getBean(name, type);
				if (!excludes.contains(bean)) {
                    // 排除项中不包含,则添加到返回结果集合
					map.put(name, bean);
				}
			}
		}
		List<Entry<String, T>> beans = new ArrayList<>();
		beans.addAll(map.entrySet());
        // 对所有的Bean排序后返回
		beans.sort(comparator);
		return beans;
	}

主要有两个核心动作:

  1.         获取javax.servlet.Filter类型beanName列表,其中包括"shiroFilterFactoryBean";
  2.         根据beanName获取Filter Bean;

1. 获取javax.servlet.Filter类型beanName列表,getOrderedBeansOfType由DefaultListableBeanFactory实现,内部调用doGetBeanNamesForType;

private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
	List<String> result = new ArrayList<>();

    // 遍历DefaultListableBeanFactory的beanDefinitionNames集合
	// Check all bean definitions.
	for (String beanName : this.beanDefinitionNames) {
		// Only consider bean as eligible if the bean name
		// is not defined as alias for some other bean.
		if (!isAlias(beanName)) {
			try {
				RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				// Only check bean definition if it is complete.
				if (!mbd.isAbstract() && (allowEagerInit ||
						(mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&
								!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
                    // 判断当前beanName对应的Bean是否是FactoryBean,"shiroFilterFactoryBean"是FactoryBean
					// In case of FactoryBean, match object created by FactoryBean.
					boolean isFactoryBean = isFactoryBean(beanName, mbd);
					BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
					boolean matchFound =
							(allowEagerInit || !isFactoryBean ||
									(dbd != null && !mbd.isLazyInit()) || containsSingleton(beanName)) &&
							(includeNonSingletons ||
									(dbd != null ? mbd.isSingleton() : isSingleton(beanName))) &&
                            // 进一步判断当前beanName对应的Bean是否匹配javax.servlet.Filter
							isTypeMatch(beanName, type);
					if (!matchFound && isFactoryBean) {
						// In case of FactoryBean, try to match FactoryBean instance itself next.
						beanName = FACTORY_BEAN_PREFIX + beanName;
						matchFound = (includeNonSingletons || mbd.isSingleton()) && isTypeMatch(beanName, type);
					}
					if (matchFound) {
                        // 当前beanName匹配javax.servlet.Filter,则加入匹配结果中
						result.add(beanName);
					}
				}
			}
			catch (CannotLoadBeanClassException ex) {
                // 此处代码省略
                ...
			}
		}
	}

    // 继续遍历DefaultListableBeanFactory的manualSingletonNames集合,添加匹配的beanName
	// Check manually registered singletons too.
	for (String beanName : this.manualSingletonNames) {
        // 基本同beanDefinitionNames
        // 此处代码省略
        ...
	}

	return StringUtils.toStringArray(result);
}

        1.1 遍历DefaultListableBeanFactory的beanDefinitionNames集合,针对beanName为"shiroFilterFactoryBean"情况;

        1.2 判断当前beanName是否是FactoryBean,满足;

        1.3 进一步判断当前beanName是否匹配javax.servlet.Filter,匹配;

public boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException {
	String beanName = transformedBeanName(name);

	// Check manually registered singletons.
	Object beanInstance = getSingleton(beanName, false);
	if (beanInstance != null && beanInstance.getClass() != NullBean.class) {
        // 如果是beanName对应的beanInstance是FactoryBean类型
		if (beanInstance instanceof FactoryBean) {
			if (!BeanFactoryUtils.isFactoryDereference(name)) {
                // 获取FactoryBean创建的Bean类型
				Class<?> type = getTypeForFactoryBean((FactoryBean<?>) beanInstance);
                // 判断Bean类型是否匹配javax.servlet.Filter
				return (type != null && typeToMatch.isAssignableFrom(type));
			}
			else {
				return typeToMatch.isInstance(beanInstance);
			}
		}
    }
    // 此处代码省略
    ...
}

                1.3.1 判断beanName对应的beanInstance是FactoryBean类型,满足;

                1.3.2 获取FactoryBean创建的Bean类型;

                        内部通过FactoryBean.getObjectType()获取本Bean工厂创建的Bean类型;

                1.3.3 判断Bean类型是否匹配javax.servlet.Filter,满足;

        1.4 当前beanName匹配javax.servlet.Filter,则加入匹配结果中;

        1.5 继续遍历DefaultListableBeanFactory的manualSingletonNames集合,添加匹配的beanName;

2. 根据beanName为"shiroFilterFactoryBean"获取Filter Bean,getBean由AbstractBeanFactory实现,内部调用doGetBean;

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

	final String beanName = transformedBeanName(name);
	Object bean;

    // 根据beanName获取singleton Bean
	// Eagerly check singleton cache for manually registered singletons.
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
		// log输出,代码省略

        // 获取BeanFactory创建的Bean
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}
    // 此处代码省略
    ...

    // 校验构建出来的Bean是否匹配指定的类型
    // Check if required type matches the type of the actual bean instance.
	if (requiredType != null && !requiredType.isInstance(bean)) {
        // 必要时转换Bean
        // 此处代码省略
        ...
    }
    // 校验通过则返回构建出来的Bean
	return (T) bean;
}

        2.1 根据beanName获取singleton Bean;

        2.2 获取BeanFactory创建的Bean;

               由AbstractAutowireCapableBeanFactory实现,内部调用父类AbstractBeanFactory的getObjectForBeanInstance实现;

protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

    // 判断beanName是否是isFactoryDereference
	// Don't let calling code try to dereference the factory if the bean isn't a factory.
	if (BeanFactoryUtils.isFactoryDereference(name)) {
		if (beanInstance instanceof NullBean) {
			return beanInstance;
		}
		if (!(beanInstance instanceof FactoryBean)) {
			throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
		}
	}

	// Now we have the bean instance, which may be a normal bean or a FactoryBean.
	// If it's a FactoryBean, we use it to create a bean instance, unless the
	// caller actually wants a reference to the factory.
	if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
		return beanInstance;
	}

	Object object = null;
	if (mbd == null) {
        // 尝试从缓存中获取Bean
		object = getCachedObjectForFactoryBean(beanName);
	}
	if (object == null) {
		// Return bean instance from factory.
		FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
		// Caches object obtained from FactoryBean if it is a singleton.
		if (mbd == null && containsBeanDefinition(beanName)) {
			mbd = getMergedLocalBeanDefinition(beanName);
		}
		boolean synthetic = (mbd != null && mbd.isSynthetic());
        // 从FactoryBean中获取Bean
		object = getObjectFromFactoryBean(factory, beanName, !synthetic);
	}
	return object;
}

                2.2.1 判断beanName是否是isFactoryDereference,不满足;

                2.2.2 尝试从缓存中获取Bean,获取不到;

                2.2.3 从FactoryBean中获取Bean;

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    // 判断Bean是否是singleton
	if (factory.isSingleton() && containsSingleton(beanName)) {
		synchronized (getSingletonMutex()) {
            // 尝试从Bean工厂缓存中获取singleton Bean
			Object object = this.factoryBeanObjectCache.get(beanName);
			if (object == null) {
                // 从FactoryBean中获取Bean
				object = doGetObjectFromFactoryBean(factory, beanName);
				// Only post-process and store if not put there already during getObject() call above
				// (e.g. because of circular reference processing triggered by custom getBean calls)
				Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
				if (alreadyThere != null) {
					object = alreadyThere;
				}
				else {
					if (shouldPostProcess) {
						if (isSingletonCurrentlyInCreation(beanName)) {
							// Temporarily return non-post-processed object, not storing it yet..
							return object;
						}
                        // singleton构建前处理,默认实现为将正在构建的beanName添加到构建集合中
						beforeSingletonCreation(beanName);
						try {
                            // singleton构建后置处理,即应用BeanPostProcessors到构建的Bean
							object = postProcessObjectFromFactoryBean(object, beanName);
						}
						catch (Throwable ex) {
							throw new BeanCreationException(beanName,
									"Post-processing of FactoryBean's singleton object failed", ex);
						}
						finally {
                            // singleton构建后的处理,默认实现为将构建完成的singleton从构建集合中移除
							afterSingletonCreation(beanName);
						}
					}
					if (containsSingleton(beanName)) {
                        // 将构建完成的singleton放入Bean工厂缓存
						this.factoryBeanObjectCache.put(beanName, object);
					}
				}
			}
			return object;
		}
	}
	// 此处代码省略
    ...
}

                        2.2.3.1 判断BeanFactory是否是singleton且包含该beanName,满足;

                        2.2.3.2 尝试从Bean工厂缓存中获取singleton Bean;

                        2.2.3.3 从FactoryBean中获取Bean;

                            最终调用factory.getObject()方法获取Bean,ShiroFilterFactoryBean内部调用createInstance创建AbstractShiroFilter实例;

protected AbstractShiroFilter createInstance() throws Exception {

    log.debug("Creating Shiro Filter instance.");

    // 校验SecurityManager的有效性
    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);
    }

    // 创建过滤器链管理器
    FilterChainManager manager = createFilterChainManager();

    // 配置路径匹配过滤器链解析器
    //Expose the constructed FilterChainManager by first wrapping it in a
    // FilterChainResolver implementation. The AbstractShiroFilter implementations
    // do not know about FilterChainManagers - only resolvers:
    PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
    chainResolver.setFilterChainManager(manager);

    // 创建SpringShiroFilter实例并返回
    //Now create a concrete ShiroFilter instance and apply the acquired SecurityManager and built
    //FilterChainResolver.  It doesn't matter that the instance is an anonymous inner class
    //here - we're just using it because it is a concrete AbstractShiroFilter instance that accepts
    //injection of the SecurityManager and FilterChainResolver:
    return new SpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
    }

                                2.2.3.3.1 校验SecurityManager的有效性;

                                2.2.3.3.2 创建过滤器链管理器;

protected FilterChainManager createFilterChainManager() {

    // 默认创建DefaultFilterChainManager,并应用全局配置到默认过滤器
    DefaultFilterChainManager manager = new DefaultFilterChainManager();
    Map<String, Filter> defaultFilters = manager.getFilters();

    // 应用全局配置到默认过滤器
    //apply global settings if necessary:
    for (Filter filter : defaultFilters.values()) {
        applyGlobalPropertiesIfNecessary(filter);
    }

    // 处理配置的过滤器
    //Apply the acquired and/or configured filters:
    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);
            }
            //'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);
        }
    }

    // 设置全局过滤器
    // set the global filters
    manager.setGlobalFilters(this.globalFilters);

    // 根据配置构建url的过滤器链
    //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);
        }
    }

    // 构建默认过滤器链,匹配任意未匹配的路径
    // create the default chain, to match anything the path matching would have missed
    manager.createDefaultChain("/**"); // TODO this assumes ANT path matching, which might be OK here

    return manager;
}

                                        2.2.3.3.2.1 默认创建DefaultFilterChainManager,并应用全局配置到默认过滤器;

                                        2.2.3.3.2.2 应用全局配置到配置的过滤器,并将过滤器添加到默认过滤器中,同名则覆盖默认过滤器;

                                        2.2.3.3.2.3 设置全局过滤器;

                                        2.2.3.3.2.4 根据配置构建url的过滤器链;

                                        2.2.3.3.2.5 构建默认过滤器链,匹配任意未匹配的路径;

                                2.2.3.3.3 配置路径匹配过滤器链解析器;

                                2.2.3.3.4 创建SpringShiroFilter实例并返回;

                        2.2.3.4 singleton构建前处理,默认实现为将正在构建的beanName添加到构建集合中;

                        2.2.3.5 singleton构建后置处理,即应用BeanPostProcessors到构建的Bean;

                        2.2.3.6 singleton构建后的处理,默认实现为将构建完成的singleton从构建集合中移除;

                        2.2.3.7 将构建完成的singleton放入Bean工厂缓存;

        2.3 校验构建出来的Bean是否匹配指定的类型;

        2.4 校验通过则返回构建出来的Bean;

3. 排除项中不包含构建的Bean,则添加到返回结果集合中;

4. 对所有的Bean排序后返回;

过滤

Spring Shiro创建了ShiroFilterFactoryBean Bean,则在处理请求的过滤器链中会存在一个过滤器AbstractShiroFilter,AbstractShiroFilter在执行过滤逻辑时,会将原过滤器链进行代理,在代理过滤器链ProxiedFilterChain中,优先将Shiro配置的过滤器链执行完,再执行原过滤器链,从而在请求被真正处理之前对请求进行权限管理相关操作;

对每一个请求,都会经过:创建过滤器链、执行过滤器链、释放过滤器链;

private void invoke(ServletRequest request, ServletResponse response,
            State state) throws IOException, ServletException {

    // 创建过滤器链
    // Get the FilterChain Here
    ApplicationFilterChain filterChain =
        ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

    // 调用过滤器链
    // Call the service() method for the allocated servlet instance
    try {
        // for includes/forwards
        if ((servlet != null) && (filterChain != null)) {
            filterChain.doFilter(request, response);
        }
        // Servlet Service Method is called by the FilterChain
    }
    // 异常处理
    // 此处代码省略
    ...

    // 释放过滤器链
    // Release the filter chain (if any) for this request
    try {
        if (filterChain != null)
        filterChain.release();
    }
    // 异常处理
    // 此处代码省略
    ...
}

1. 为当前请求创建过滤器链ApplicationFilterChain;

public static ApplicationFilterChain createFilterChain(ServletRequest request,
        Wrapper wrapper, Servlet servlet) {

    // If there is no servlet to execute, return null
    if (servlet == null)
        return null;

    // 创建并初始化ApplicationFilterChain
    // Create and initialize a filter chain object
    ApplicationFilterChain filterChain = null;
    // 此处代码省略
    ...

    // 从上下文StandardContext中获取过滤器映射集合
    // Acquire the filter mappings for this Context
    StandardContext context = (StandardContext) wrapper.getParent();
    FilterMap filterMaps[] = context.findFilterMaps();

    // 如果过滤器映射集合为空,则直接返回ApplicationFilterChain
    // If there are no filter mappings, we are done
    if ((filterMaps == null) || (filterMaps.length == 0))
        return (filterChain);

    // Acquire the information we will need to match filter mappings
    DispatcherType dispatcher =
        (DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR);

    String requestPath = null;
    Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR);
    if (attribute != null){
        requestPath = attribute.toString();
    }

    String servletName = wrapper.getName();

    // 遍历过滤器映射集合,将路径匹配的过滤器加入到处理该请求的过滤器链
    // Add the relevant path-mapped filters to this filter chain
    for (int i = 0; i < filterMaps.length; i++) {
        // 是否匹配dispatcher
        if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
            continue;
        }
        // 是否匹配请求路径
        if (!matchFiltersURL(filterMaps[i], requestPath))
            continue;
        ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
            context.findFilterConfig(filterMaps[i].getFilterName());
        if (filterConfig == null) {
            // FIXME - log configuration problem
            continue;
        }
        // 添加过滤器
        filterChain.addFilter(filterConfig);
    }

    // 遍历过滤器映射集合,将Servlet名称匹配的过滤器加入到处理该请求的过滤器链
    // Add filters that match on servlet name second
    for (int i = 0; i < filterMaps.length; i++) {
        // 是否匹配dispatcher
        if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
            continue;
        }
        // 是否匹配Servlet名称
        if (!matchFiltersServlet(filterMaps[i], servletName))
            continue;
        ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
            context.findFilterConfig(filterMaps[i].getFilterName());
        if (filterConfig == null) {
            // FIXME - log configuration problem
            continue;
        }
        // 添加过滤器
        filterChain.addFilter(filterConfig);
    }

    // 返回过滤器链
    // Return the completed filter chain
    return filterChain;
}

        1.1 从上下文StandardContext从获取过滤器映射集合;

            过滤器映射集合包含的过滤器如下:

                1. characterEncodingFilter -> OrderedCharacterEncodingFilter

                2. hiddenHttpMethodFilter -> OrderedHiddenHttpMethodFilter

                3. httpPutFormContentFilter -> OrderedHttpPutFormContentFilter

                4. requestContextFilter -> OrderedRequestContextFilter

                5. filterName -> StatViewFilter

                6. shiroFilterFactoryBean -> ShiroFilterFactoryBean$SpringShiroFilter(Shiro)

                7. filterName -> WsFilter

            匹配的路径都是 /*,即全匹配;

        1.2 遍历过滤器映射集合,将路径匹配的过滤器加入到处理该请求的过滤器链;

void addFilter(ApplicationFilterConfig filterConfig) {

    // 遍历当前已存在的过滤器列表
    // Prevent the same filter being added multiple times
    for(ApplicationFilterConfig filter:filters)
        if(filter==filterConfig)
            // 若已存在,则无需添加,直接返回
            return;

    // 校验过滤器列表长度,如果无空间存储,则扩容(容量增10)
    if (n == filters.length) {
        ApplicationFilterConfig[] newFilters =
            new ApplicationFilterConfig[n + INCREMENT];
        System.arraycopy(filters, 0, newFilters, 0, n);
        filters = newFilters;
    }
    // 添加到过滤器列表
    filters[n++] = filterConfig;
}

                1.2.1 遍历当前已存在的过滤器列表,若已存在,则无需添加,直接返回;                  

                1.2.2 校验过滤器列表长度,如果无空间存储,则扩容(容量增10);

                1.2.3 添加到过滤器列表;

        1.3 遍历过滤器映射集合,将Servlet名称匹配的过滤器加入到处理该请求的过滤器链;

            添加过滤器逻辑同1.2;

        1.4 返回过滤器链;

2. 执行过滤器链;

    过滤器链成功执行完后会调用servlet.service(request, response);

    非安全模式直接调用internalDoFilter(request, response);

private void internalDoFilter(ServletRequest request, ServletResponse response)
        throws IOException, ServletException {

    // 执行过滤器列表中下一个过滤器的过滤逻辑;
    // 过滤器执行完过滤逻辑后,
    //     要么调用filterChain.doFilter方法,继续下一个过滤器的处理;
    //     要么设置Response,直接返回;
    //     要么抛出异常,由StandardWrapperValve设置Response;
    // Call the next filter if there is one
    if (pos < n) {
        ApplicationFilterConfig filterConfig = filters[pos++];
        try {
            // 获取过滤器
            Filter filter = filterConfig.getFilter();

            if (request.isAsyncSupported() && "false".equalsIgnoreCase(
                    filterConfig.getFilterDef().getAsyncSupported())) {
                request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
            }
            if( Globals.IS_SECURITY_ENABLED ) {
                final ServletRequest req = request;
                final ServletResponse res = response;
                Principal principal =
                    ((HttpServletRequest) req).getUserPrincipal();

                Object[] args = new Object[]{req, res, this};
                SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
            } else {
                // 执行过滤器
                filter.doFilter(request, response, this);
            }
        } catch (IOException | ServletException | RuntimeException e) {
            throw e;
        } catch (Throwable e) {
            e = ExceptionUtils.unwrapInvocationTargetException(e);
            ExceptionUtils.handleThrowable(e);
            throw new ServletException(sm.getString("filterChain.filter"), e);
        }
        return;
    }

    // 成功遍历完过滤器列表,则处理请求
    // We fell off the end of the chain -- call the servlet instance
    try {
        if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
            lastServicedRequest.set(request);
            lastServicedResponse.set(response);
        }

        if (request.isAsyncSupported() && !servletSupportsAsync) {
            request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
        }
        // Use potentially wrapped request from this point
        if ((request instanceof HttpServletRequest) &&
                (response instanceof HttpServletResponse) &&
                Globals.IS_SECURITY_ENABLED ) {
            final ServletRequest req = request;
            final ServletResponse res = response;
            Principal principal =
                ((HttpServletRequest) req).getUserPrincipal();
            Object[] args = new Object[]{req, res};
            SecurityUtil.doAsPrivilege("service",
                                       servlet,
                                       classTypeUsedInService,
                                       args,
                                       principal);
        } else {
            servlet.service(request, response);
        }
    } catch (IOException | ServletException | RuntimeException e) {
        throw e;
    } catch (Throwable e) {
        e = ExceptionUtils.unwrapInvocationTargetException(e);
        ExceptionUtils.handleThrowable(e);
        throw new ServletException(sm.getString("filterChain.servlet"), e);
    } finally {
        if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
            lastServicedRequest.set(null);
            lastServicedResponse.set(null);
        }
    }
}

        2.1 执行过滤器列表中下一个过滤器的过滤逻辑;

            过滤器执行完过滤逻辑后,

                要么调用filterChain.doFilter方法,继续下一个过滤器的处理;

                要么设置Response,直接返回;

                要么抛出异常,由StandardWrapperValve设置Response;

            本文只关注ShiroFilterFactoryBean$SpringShiroFilter的过滤逻辑;

protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, final FilterChain chain) throws ServletException, IOException {

    Throwable t = null;

    try {
        final ServletRequest request = prepareServletRequest(servletRequest, servletResponse, chain);
        final ServletResponse response = prepareServletResponse(request, servletResponse, chain);

        // 创建Subject
        final Subject subject = createSubject(request, response);

        // 创建任务线程执行过滤器链
        //noinspection unchecked
        subject.execute(new Callable() {
            public Object call() throws Exception {
                updateSessionLastAccessTime(request, response);
                executeChain(request, response, chain);
                return null;
            }
        });
    } catch (ExecutionException ex) {
        t = ex.getCause();
    } catch (Throwable throwable) {
        t = throwable;
    }

    if (t != null) {
        if (t instanceof ServletException) {
            throw (ServletException) t;
        }
        if (t instanceof IOException) {
            throw (IOException) t;
        }
        //otherwise it's not one of the two exceptions expected by the filter method signature - wrap it in one:
        String msg = "Filtered request failed.";
        throw new ServletException(msg, t);
    }
}

                2.1.1 创建Subject

                2.1.2 创建任务线程执行过滤器链;

protected void executeChain(ServletRequest request, ServletResponse response, FilterChain origChain) throws IOException, ServletException {
    // 构造该请求的代理过滤器链
    FilterChain chain = getExecutionChain(request, response, origChain);
    // 执行过滤器链
    chain.doFilter(request, response);
}

                        2.1.2.1 构造该请求的代理过滤器链;

                            内部由PathMatchingFilterChainResolver.getChain构造代理过滤器链,若无需代理,则返回原过滤器链;

public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) {
    FilterChainManager filterChainManager = getFilterChainManager();
    if (!filterChainManager.hasChains()) {
        // 若FilterChainManager无配置的过滤器,则无需代理,直接返回null
        return null;
    }

    final String requestURI = getPathWithinApplication(request);
    final String requestURINoTrailingSlash = removeTrailingSlash(requestURI);

    // 遍历FilterChainManager中配置的过滤器链集合
    //the 'chain names' in this implementation are actually path patterns defined by the user.  We just use them
    //as the chain name for the FilterChainManager's requirements
    for (String pathPattern : filterChainManager.getChainNames()) {
        // If the path does match, then pass on to the subclass implementation for specific checks:
        // 判断Request的路径匹配是否已配置的过滤器链的路径
        // 借助PatternMatcher判断两个路径是否匹配
        if (pathMatches(pathPattern, requestURI)) {
            if (log.isTraceEnabled()) {
                log.trace("Matched path pattern [{}] for requestURI [{}].  " +
                        "Utilizing corresponding filter chain...", pathPattern, Encode.forHtml(requestURI));
            }
            // 匹配成功,则代理原过滤器链
            return filterChainManager.proxy(originalChain, pathPattern);
        } else {

            // in spring web, the requestURI "/resource/menus" ---- "resource/menus/" bose can access the resource
            // but the pathPattern match "/resource/menus" can not match "resource/menus/"
            // user can use requestURI + "/" to simply bypassed chain filter, to bypassed shiro protect
            // 去除尾部路径符,再匹配一次
            pathPattern = removeTrailingSlash(pathPattern);

            if (pathMatches(pathPattern, requestURINoTrailingSlash)) {
                if (log.isTraceEnabled()) {
                    log.trace("Matched path pattern [{}] for requestURI [{}].  " +
                              "Utilizing corresponding filter chain...", pathPattern, Encode.forHtml(requestURINoTrailingSlash));
                }
                // 匹配成功,则代理原过滤器链
                return filterChainManager.proxy(originalChain, requestURINoTrailingSlash);
            }
        }
    }

    // 无需代理,返回null
    return null;
}

                                2.1.2.1.1 若FilterChainManager无配置的过滤器,则无需代理,直接返回null;

                                2.1.2.1.2 遍历FilterChainManager中配置的过滤器链集合;

                                2.1.2.1.3 判断Request的路径匹配是否已配置的过滤器链的路径;

                                    借助PatternMatcher判断两个路径是否匹配,Shiro框架中存在默认过滤器链("/**"),会匹配任意URL;

                                2.1.2.1.4 若匹配成功,则代理原过滤器链;                                  

                                    代理的过滤器链为ProxiedFilterChain;

                        2.1.2.2 执行过滤器链;

                            若存在代理,则为ProxiedFilterChain.doFilter(request, response);

public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
    if (this.filters == null || this.filters.size() == this.index) {
        //we've reached the end of the wrapped chain, so invoke the original one:
        if (log.isTraceEnabled()) {
            log.trace("Invoking original filter chain.");
        }
        // 过滤器集合为空,或者已全部执行完,则执行原过滤器链
        this.orig.doFilter(request, response);
    } else {
        if (log.isTraceEnabled()) {
            log.trace("Invoking wrapped filter at index [" + this.index + "]");
        }
        // 执行过滤器集合中下一个过滤器的过滤逻辑
        this.filters.get(this.index++).doFilter(request, response, this);
    }
}

                                2.1.2.2.1 如果过滤器集合为空,或者已全部执行完,则执行原过滤器链;

                                2.1.2.2.2 执行过滤器集合中下一个过滤器的过滤逻辑;

                                    以FormAuthenticationFilter举例;

                                        2.1.2.2.2.1 调用OncePerRequestFilter.doFilter算法模板,保证只执行一次过滤逻辑;

                                        2.1.2.2.2.2 调用AdviceFilter.doFilterInternal算法模板,进行preHandle/executeChain(如果preHandle返回false则不调用)/postHandle/cleanup处理;

                                        2.1.2.2.2.3 调用PathMatchingFilter.preHandle算法模板,如果需要拦截请求,则进行isFilterChainContinued处理;

                                        2.1.2.2.2.4 调用AccessControlFilter.onPreHandle算法模板,进行isAccessAllowed/onAccessDenied处理;

                                        2.1.2.2.2.5 调用AuthenticatingFilter.isAccessAllowed方法,内部会调用父类AuthenticationFilter.isAccessAllowed方法,判断当前用户是否已登录;

                                        2.1.2.2.2.6 调用FormAuthenticationFilter.onAccessDenied方法,进行登录尝试,或者跳转到登录页面;

        2.2 成功遍历完过滤器列表,则处理请求;

servlet.service(request, response);

3. 释放过滤器链;

    清除过滤器列表等信息;

void release() {
    // 释放过滤器列表
    for (int i = 0; i < n; i++) {
        filters[i] = null;
    }

    // 清除信息
    n = 0;
    pos = 0;
    servlet = null;
    servletSupportsAsync = false;
}

标签:beanName,request,Bean,简析,过滤器,2.2,null,Shiro
来源: https://blog.csdn.net/xing_hung/article/details/121500539

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有