浅谈Spring与Filter&Interceptor解析过程
字数 2359 2025-08-06 08:35:06

Spring与Filter&Interceptor解析过程详解

0x00 前言

过滤器(Filter)与拦截器(Interceptor)的区别

特性 Filter Interceptor
标准 JavaEE标准 Spring框架特有
依赖 Servlet容器 Spring等Web框架
配置位置 web.xml或注解 SpringMVC配置文件或注解
实现机制 函数回调 AOP应用,Java反射机制
Bean注入 不能注入Spring Bean 可以注入Spring Bean
拦截范围 所有请求 仅Controller请求和static资源目录下的请求
执行顺序 优先于Interceptor 在Filter之后执行

0x01 过滤器Filter

1.1 Spring中Filter的使用方式

1.1.1 在web.xml配置

<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

1.1.2 通过@WebFilter注解配置

@WebFilter(urlPatterns = "/*")
public class InvalidRequestFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
        // 处理逻辑
        chain.doFilter(request, response);
    }
}

启动类添加@ServletComponentScan注解:

@SpringBootApplication
@ServletComponentScan("Filter对应的包路径")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

1.1.3 通过@Bean配置

@Component
public class InvalidRequestFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
        // 处理逻辑
        chain.doFilter(request, response);
    }
}

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Bean
    public FilterRegistrationBean<InvalidRequestFilter> FilterConfig() {
        FilterRegistrationBean<InvalidRequestFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new InvalidRequestFilter());
        registrationBean.addUrlPatterns("/*");
        return registrationBean;
    }
}

1.2 Filter过滤器调用过程分析

  1. 调用入口org.apache.catalina.core.StandardWrapperValve#invoke()
  2. 创建FilterChainApplicationFilterFactory.createFilterChain()
    • 检查servlet是否为null
    • 创建或获取已存在的过滤器链对象
    • 获取所有filter的映射对象(filterMaps)
  3. 匹配逻辑
    • 获取请求的调度类型(dispatcher)和请求路径(requestPath)
    • 遍历过滤器映射,根据条件匹配
  4. 执行流程
    • ApplicationFilterChain#doFilter
    • ApplicationFilterChain#internalDoFilter
    • 通过pos索引判断是否执行完所有filter
    • 执行完所有filter后执行servlet业务模块

1.2.1 Filter的匹配逻辑

  1. dispatcher类型:默认为DispatcherType.REQUEST
  2. requestPath获取
    • 从request的org.apache.catalina.core.DISPATCHER_REQUEST_PATH属性获取
    • 实际来自mappingData.requestPath
    • 经过parsePathParameters()normalize()处理
  3. 匹配条件
    • 类型和路径都匹配
    • 类型和servlet名称都匹配
  4. 匹配函数
    • matchDispatcher(filterMap, dispatcher)
    • matchFiltersURL(filterMap, requestPath)
    • matchFiltersServlet(filterMap, servletName)

路径匹配规则

  • 完全相等
  • /*匹配所有
  • /*结尾的前缀匹配
  • *.开头的扩展名匹配

0x02 拦截器Interceptor

2.1 Spring中Interceptor的使用

public class AuthInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 前置处理逻辑
        return true;
    }
}

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AuthInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/test/**");
    }
}

2.2 Interceptor拦截器调用过程分析

  1. 调用入口DispatcherServlet#doDispatch()
  2. 获取HandlerExecutionChain
    • RequestMappingHandlerMapping.getHandler()
    • getHandlerInternal()获取handler
    • 构建HandlerExecutionChain并添加Interceptor
  3. 执行流程
    • applyPreHandle()执行前置处理
    • 执行Controller服务
    • applyPostHandle()执行后置处理
    • triggerAfterCompletion()执行完成处理

2.2.1 Interceptor的匹配逻辑

  1. 获取请求路径ServletRequestPathUtils.getCachedPath()
  2. 匹配模式
    • 默认使用AntPathMatcher
    • 高版本可能使用PathPatternParser
  3. 匹配过程
    • 检查excludePatternsincludePatterns
    • 根据路径类型调用不同匹配器
    • 对路径进行规范化处理

0x03 潜在的安全问题

3.1 解析差异导致的Filter失效

问题原因

  • Spring高版本使用PathPattern进行路径匹配
  • Filter基于Servlet的匹配逻辑
  • 两者解析规则存在差异

示例场景

@RestController
@RequestMapping("/admin")
public class AdminController {
    @RequestMapping(value = "/page", method = RequestMethod.GET)
    public String page() {
        return "admin page";
    }
}

Filter配置

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Bean
    public FilterRegistrationBean<InvalidRequestFilter> FilterConfig() {
        FilterRegistrationBean<InvalidRequestFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new InvalidRequestFilter());
        registrationBean.addUrlPatterns("/admin/*");
        return registrationBean;
    }
}

绕过方式

  • /admin/../page; 可能绕过Filter检查
  • 因为Tomcat会规范化路径,而Spring可能不会

解决方案

  • 使用Spring Security的HTTP Firewall Filter
  • 避免自行实现安全相关的Filter

0x04 最佳实践

  1. 路径匹配

    • 了解Filter和Interceptor的不同匹配规则
    • 注意Tomcat和Spring的路径解析差异
  2. 安全防护

    • 优先使用成熟安全框架(如Spring Security)
    • 避免在Filter中实现关键安全逻辑
  3. 性能考虑

    • Filter适用于全局性、与业务无关的处理
    • Interceptor适用于与业务相关的处理
  4. 版本兼容

    • 注意Spring版本升级带来的路径匹配变化
    • 测试不同路径模式下的行为一致性
Spring与Filter&Interceptor解析过程详解 0x00 前言 过滤器(Filter)与拦截器(Interceptor)的区别 | 特性 | Filter | Interceptor | |------|--------|-------------| | 标准 | JavaEE标准 | Spring框架特有 | | 依赖 | Servlet容器 | Spring等Web框架 | | 配置位置 | web.xml或注解 | SpringMVC配置文件或注解 | | 实现机制 | 函数回调 | AOP应用,Java反射机制 | | Bean注入 | 不能注入Spring Bean | 可以注入Spring Bean | | 拦截范围 | 所有请求 | 仅Controller请求和static资源目录下的请求 | | 执行顺序 | 优先于Interceptor | 在Filter之后执行 | 0x01 过滤器Filter 1.1 Spring中Filter的使用方式 1.1.1 在web.xml配置 1.1.2 通过@WebFilter注解配置 启动类添加 @ServletComponentScan 注解: 1.1.3 通过@Bean配置 1.2 Filter过滤器调用过程分析 调用入口 : org.apache.catalina.core.StandardWrapperValve#invoke() 创建FilterChain : ApplicationFilterFactory.createFilterChain() 检查servlet是否为null 创建或获取已存在的过滤器链对象 获取所有filter的映射对象(filterMaps) 匹配逻辑 : 获取请求的调度类型(dispatcher)和请求路径(requestPath) 遍历过滤器映射,根据条件匹配 执行流程 : ApplicationFilterChain#doFilter ApplicationFilterChain#internalDoFilter 通过pos索引判断是否执行完所有filter 执行完所有filter后执行servlet业务模块 1.2.1 Filter的匹配逻辑 dispatcher类型 :默认为 DispatcherType.REQUEST requestPath获取 : 从request的 org.apache.catalina.core.DISPATCHER_REQUEST_PATH 属性获取 实际来自 mappingData.requestPath 经过 parsePathParameters() 和 normalize() 处理 匹配条件 : 类型和路径都匹配 类型和servlet名称都匹配 匹配函数 : matchDispatcher(filterMap, dispatcher) matchFiltersURL(filterMap, requestPath) matchFiltersServlet(filterMap, servletName) 路径匹配规则 : 完全相等 /* 匹配所有 /* 结尾的前缀匹配 *. 开头的扩展名匹配 0x02 拦截器Interceptor 2.1 Spring中Interceptor的使用 2.2 Interceptor拦截器调用过程分析 调用入口 : DispatcherServlet#doDispatch() 获取HandlerExecutionChain : RequestMappingHandlerMapping.getHandler() getHandlerInternal() 获取handler 构建 HandlerExecutionChain 并添加Interceptor 执行流程 : applyPreHandle() 执行前置处理 执行Controller服务 applyPostHandle() 执行后置处理 triggerAfterCompletion() 执行完成处理 2.2.1 Interceptor的匹配逻辑 获取请求路径 : ServletRequestPathUtils.getCachedPath() 匹配模式 : 默认使用 AntPathMatcher 高版本可能使用 PathPatternParser 匹配过程 : 检查 excludePatterns 和 includePatterns 根据路径类型调用不同匹配器 对路径进行规范化处理 0x03 潜在的安全问题 3.1 解析差异导致的Filter失效 问题原因 : Spring高版本使用 PathPattern 进行路径匹配 Filter基于Servlet的匹配逻辑 两者解析规则存在差异 示例场景 : Filter配置 : 绕过方式 : /admin/../page; 可能绕过Filter检查 因为Tomcat会规范化路径,而Spring可能不会 解决方案 : 使用Spring Security的 HTTP Firewall Filter 避免自行实现安全相关的Filter 0x04 最佳实践 路径匹配 : 了解Filter和Interceptor的不同匹配规则 注意Tomcat和Spring的路径解析差异 安全防护 : 优先使用成熟安全框架(如Spring Security) 避免在Filter中实现关键安全逻辑 性能考虑 : Filter适用于全局性、与业务无关的处理 Interceptor适用于与业务相关的处理 版本兼容 : 注意Spring版本升级带来的路径匹配变化 测试不同路径模式下的行为一致性