简介
本文简单分析Spring Shiro框架中过滤器的使用,涉及过滤器的配置、初始化过程、过滤流程;
配置
Shiro中对过滤器的配置,核心是对ShiroFilterFactoryBean的配置,主要分为三部分:
- 配置SecurityManager;
- 配置过滤器;
- 配置请求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;
}
主要有两个核心动作:
- 获取javax.servlet.Filter类型beanName列表,其中包括"shiroFilterFactoryBean";
- 根据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;
}