Spring Security 中的过滤器(`Filter`)和拦截器(`HandlerInterceptor`)

发布于:2025-06-24 ⋅ 阅读:(17) ⋅ 点赞:(0)

🤟致敬读者

  • 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉

📘博主相关



📃文章前言

  • 🔷文章均为学习工作中整理的笔记。
  • 🔶如有错误请指正,共同学习进步。

Spring Security 中的过滤器(Filter)和拦截器(HandlerInterceptor

理解 Spring Security 中的过滤器(Filter)和拦截器(HandlerInterceptor)对于面试和实际应用都至关重要。它们在请求处理流程中扮演着不同但有时又协同的角色。下面进行详细解析:

核心概念区分

  1. 过滤器 (javax.servlet.Filter):

    • 归属: Servlet 规范 (J2EE) 定义的标准组件。不依赖于任何特定框架(如 Spring)。
    • 作用范围: 作用于 Servlet 容器级别。任何进入 Servlet 容器(如 Tomcat, Jetty)的请求和离开容器的响应都会经过配置的过滤器链。
    • 职责:
      • 在请求到达 Servlet (通常是 Spring MVC 的 DispatcherServlet) 之前执行预处理逻辑。
      • 在响应离开 Servlet 之后执行后处理逻辑。
      • 可以修改请求 (HttpServletRequest)修改响应 (HttpServletResponse)
      • 可以中断请求处理链(例如,直接返回响应、重定向)。
    • 生命周期: 由 Servlet 容器管理。
    • 访问信息: 主要访问 ServletRequestServletResponse。它们对 Spring 的上下文(如 ApplicationContext, beans)没有直接访问权限(除非通过特殊手段如 SpringBeanAutowiringSupport,但一般不推荐在 Filter 中直接注入 Bean)。
  2. 拦截器 (org.springframework.web.servlet.HandlerInterceptor):

    • 归属: Spring MVC 框架定义的组件。
    • 作用范围: 作用于 Spring MVC 的 DispatcherServlet 内部。只有被 DispatcherServlet 路由的请求(即映射到 @Controller 的请求)才会经过配置的拦截器链。
    • 职责:
      • Controller 方法执行之前 (preHandle) 执行预处理逻辑。
      • Controller 方法执行之后、视图渲染之前 (postHandle) 执行后处理逻辑(如果 Controller 方法成功执行)。
      • 整个请求完成之后(视图渲染之后或发生异常之后)(afterCompletion) 执行清理逻辑(无论 Controller 方法是否成功执行)。
      • 可以访问 HandlerMethod (即将要执行的 Controller 方法对象) 和 ModelAndView (在 postHandle 中)。
      • 可以中断 Controller 方法的执行(在 preHandle 中返回 false)。
    • 生命周期: 由 Spring 的 ApplicationContext 管理。因此,可以方便地使用依赖注入@Autowired, @Resource 等)获取其他 Spring Bean。
    • 访问信息: 可以访问 Spring MVC 的特定对象,如 HandlerMethod, ModelAndView

执行顺序图示

理解它们在请求处理管道中的位置是关键:

  HTTP Request
        ↓
  Servlet Container (Tomcat, Jetty, etc.)
        ↓
  ---> [Filter 1] ---> [Filter 2] ---> ... ---> [Filter N] ---> (Spring Security's FilterChainProxy is usually here!)
        ↓
  DispatcherServlet (Spring MVC Entry Point)
        ↓
  ---> [Interceptor 1.preHandle]
        ↓
  ---> [Interceptor 2.preHandle]
        ↓
        ... (All Interceptors' preHandle called in order)
        ↓
  ---> HandlerAdapter (Actually invokes the Controller method)
        ↓
  ---> [Interceptor 2.postHandle] <--- (Reverse order!)
        ↓
  ---> [Interceptor 1.postHandle] <---
        ↓
  View Rendering (if applicable)
        ↓
  ---> [Interceptor 2.afterCompletion] <--- (Reverse order! Called regardless of success/exception)
        ↓
  ---> [Interceptor 1.afterCompletion] <---
        ↓
  DispatcherServlet
        ↓
  <--- [Filter N] <--- ... <--- [Filter 2] <--- [Filter 1] <--- (Response processing)
        ↓
  HTTP Response
  • 关键点 1: 所有过滤器 (Filter) 都在 DispatcherServlet 之前执行。 这意味着 Spring Security 的核心安全逻辑(认证、授权、CSRF 保护等)必须作为过滤器来实现,因为它们需要在请求进入 Spring MVC 的核心处理流程(包括 Controller 和 Interceptor)之前完成安全检查。
  • 关键点 2: 拦截器 (HandlerInterceptor) 在 DispatcherServlet 内部,Controller 方法执行前后执行。 它们工作在 Spring MVC 的上下文中,可以感知 Controller 方法级别的信息。

Spring Security 如何利用过滤器

  • FilterChainProxy: 这是 Spring Security 的核心入口。它本身就是一个特殊的 Filter (通常注册在 Servlet 容器过滤器链中一个靠前的位置,比如 /*)。它的工作是管理和协调 Spring Security 内部定义的一系列安全过滤器 (SecurityFilterChain)
  • SecurityFilterChain: 包含一组有序的、特定于 Spring Security 的 Filter 实现。每个 SecurityFilterChain 可以匹配不同的请求模式(如 /api/**, /admin/**)。
  • 典型的安全过滤器:
    • SecurityContextPersistenceFilter: 在请求开始时从 SecurityContextRepository (默认是 HttpSessionSecurityContextRepository) 加载 SecurityContext (包含认证信息),在请求结束时保存它(如果需要)。
    • UsernamePasswordAuthenticationFilter: 处理基于表单的登录 (POST /login)。
    • BasicAuthenticationFilter: 处理 HTTP Basic 认证。
    • BearerTokenAuthenticationFilter: 处理 OAuth2 Bearer Token 认证 (JWT 等)。
    • AnonymousAuthenticationFilter: 如果请求还没有认证信息,创建一个 AnonymousAuthenticationToken 代表匿名用户。
    • SessionManagementFilter: 处理会话固定保护、并发会话控制等。
    • ExceptionTranslationFilter: 捕获安全过滤器链中抛出的 AccessDeniedExceptionAuthenticationException,并触发相应的入口点 (AuthenticationEntryPoint) 或拒绝访问处理器 (AccessDeniedHandler)。
    • FilterSecurityInterceptor: 这是授权决策的核心。它从 SecurityContextHolder 获取 Authentication 对象,然后使用 AccessDecisionManager 基于配置的安全规则(SecurityMetadataSource,通常来自 @PreAuthorize, @Secured, http.authorizeRequests() 等)决定是否允许访问目标资源。如果拒绝,则抛出 AccessDeniedException(注意:虽然名字叫 Interceptor,但它是一个 Filter! 这是历史原因造成的命名)
    • CsrfFilter: 提供对 CSRF 攻击的保护。
    • LogoutFilter: 处理注销请求 (POST /logout)。

拦截器在 Spring Security 中的角色(较少)

在 Spring Security 本身的核心功能实现中,直接使用 HandlerInterceptor 的情况相对较少。安全的核心逻辑(特别是认证和授权)必须在请求到达 Controller 之前完成,这天然适合在过滤器链中实现。

然而,拦截器可以在与安全相关的辅助功能特定于 Controller 的安全增强方面发挥作用:

  1. 审计日志 (Auditing): 在拦截器的 preHandlepostHandle 中记录谁(从 SecurityContextHolder 获取 Authentication)在什么时候访问了哪个 Controller 方法 (HandlerMethod)。
  2. 细粒度的后处理: 在 postHandle 中基于安全上下文修改 ModelAndView(例如,根据用户角色在模型中设置不同的视图标志)。
  3. 自定义逻辑与 Controller 方法紧密结合: 如果需要基于即将执行的 Controller 方法或其注解进行非常特定的安全检查或处理,且这个逻辑不适合放在全局安全规则(@PreAuthorize)或 AOP 中,可以考虑使用拦截器。但要谨慎,因为此时请求已经通过了主要的 FilterSecurityInterceptor 授权检查。
  4. 清理或资源释放: 在 afterCompletion 中执行一些与安全相关的清理工作(虽然过滤器通常也能做)。

面试回答要点与建议

  1. 清晰区分概念:

    • 强调 Filter 是 Servlet 规范,作用于容器层,在 DispatcherServlet 之前;Interceptor 是 Spring MVC 组件,作用于 DispatcherServlet 内部,围绕 Controller 方法执行。
    • Spring Security 的核心安全机制(认证、授权)必须构建在 Filter 上,因为它们需要在请求进入 Spring MVC 核心流程前完成。
    • 明确指出 FilterSecurityInterceptor 虽然叫 Interceptor,但它是一个 Filter
  2. 阐述 Spring Security 的过滤器链机制:

    • 提到 FilterChainProxy 作为总入口。
    • 解释 SecurityFilterChain 的作用(匹配请求路径)。
    • 列举几个关键的安全过滤器及其作用(SecurityContextPersistenceFilter, UsernamePasswordAuthenticationFilter, ExceptionTranslationFilter, FilterSecurityInterceptor, CsrfFilter)。
  3. 说明拦截器的适用场景(在安全上下文中):

    • 主要用于辅助功能(如审计日志)或与 Controller 方法紧密相关的后处理
    • 强调在 Spring Security 本身中直接使用 Interceptor 较少,核心逻辑在 Filter 链。
  4. 执行顺序的重要性:

    • 明确画出或描述请求经过 Servlet Filter(s) -> Spring Security FilterChain (via FilterChainProxy) -> DispatcherServlet -> Spring MVC Interceptor(s) -> Controller 的流程。特别指出 Spring Security 的 Filter 在 Interceptor 之前执行
  5. 依赖注入:

    • 指出 Interceptor 作为 Spring Bean 可以方便地使用 DI,而原生的 Filter 不能直接使用 Spring DI(需要额外配置,如 DelegatingFilterProxyFilterRegistrationBean 结合 Spring 管理的 Filter Bean)。
  6. 何时用哪个?

    • 需要全局性的、在请求处理最早阶段介入的安全控制(认证、授权、CSRF)? -> Filter (特别是使用 Spring Security 提供的 Filter)。
    • 需要访问 Spring MVC 特定对象(HandlerMethod, ModelAndView)、进行基于 Controller 方法的细粒度操作(如审计)? -> Interceptor
    • 需要在视图渲染前后执行逻辑? -> Interceptor (postHandle, afterCompletion)。
    • 需要修改请求/响应内容本身(如包装 HttpServletRequest)? -> Filter (Interceptor 无法修改请求体/响应体)。
  7. 常见误区澄清:

    • 误区: “Spring Security 用 Interceptor 做授权。” 澄清: 核心授权是 FilterSecurityInterceptor (一个 Filter!) 做的。
    • 误区: “Interceptor 可以做认证。” 澄清: 理论上可以,但极其不推荐。认证必须在更早的 Filter 阶段完成。在 Interceptor 做认证太晚,且绕过 Spring Security 的核心机制,会导致漏洞和不一致。
    • 误区: “Interceptor 可以替代 Filter。” 澄清: 不能。作用范围和能力不同。它们是互补的。

示例面试回答结构

“在 Java Web 应用和 Spring Security 中,过滤器 (Filter) 和拦截器 (HandlerInterceptor) 都是处理 HTTP 请求响应的组件,但层次和职责不同。

  • 过滤器 (Filter) 是 Servlet 规范定义的,工作在 Servlet 容器层面。任何请求进入容器后,响应离开容器前,都会经过配置的过滤器链。它们能修改请求和响应,并能中断链。Spring Security 的核心安全功能完全建立在过滤器链之上。关键组件 FilterChainProxy 本身就是一个 Filter,它内部管理着多个 SecurityFilterChain,每个链包含一系列安全过滤器,例如:

    • SecurityContextPersistenceFilter:管理安全上下文(用户认证信息)。
    • UsernamePasswordAuthenticationFilter:处理表单登录。
    • ExceptionTranslationFilter:处理认证授权异常。
    • FilterSecurityInterceptor核心的授权过滤器,决定当前用户是否有权访问资源。
    • CsrfFilter:防范 CSRF 攻击。 这些过滤器必须在请求到达 Spring MVC 的 DispatcherServlet (以及任何 Controller) 之前执行安全检查。
  • 拦截器 (HandlerInterceptor) 是 Spring MVC 框架定义的,工作在 DispatcherServlet 内部。它们在 Controller 方法执行的前(preHandle)、后(postHandle)、以及整个请求完成后(afterCompletion)被调用。它们能访问 Spring MVC 对象(如 HandlerMethod),方便使用 Spring DI,但不能修改原始请求/响应体内容。在 Spring Security 的核心功能实现中,拦截器使用较少,因为安全决策需要在更早的 Filter 阶段完成。拦截器更多用于:

    • 审计日志(记录哪个认证用户访问了哪个 Controller 方法)。
    • 基于安全上下文的视图模型修改。
    • 与特定 Controller 方法相关的后处理逻辑。

执行顺序上: HTTP Request -> Servlet Filters (包括 FilterChainProxy 和 Spring Security 内部过滤器) -> DispatcherServlet -> Spring MVC Interceptors (preHandle) -> Controller -> Interceptors (postHandle) -> View Render -> Interceptors (afterCompletion) -> Servlet Filters (响应处理) -> HTTP Response。

总结:对于安全,认证授权等核心机制必须通过过滤器(特别是 Spring Security 的过滤器链)在请求进入 MVC 核心前完成。拦截器更适合 MVC 内部的、与 Controller 方法执行生命周期紧密相关的辅助性功能。两者协同工作,但职责清晰不同。”

记住,结合具体的过滤器名称(尤其是 FilterSecurityInterceptor)和清晰的执行流程图(即使在脑中描述)会让你的回答更有说服力。祝你面试顺利!


📜文末寄语

  • 🟠关注我,获取更多内容。
  • 🟡技术动态、实战教程、问题解决方案等内容持续更新中。
  • 🟢《全栈知识库》技术交流和分享社区,集结全栈各领域开发者,期待你的加入。
  • 🔵​加入开发者的《专属社群》,分享交流,技术之路不再孤独,一起变强。
  • 🟣点击下方名片获取更多内容🍭🍭🍭👇


网站公告

今日签到

点亮在社区的每一天
去签到