一个开发者对 Spring Security 拦截机制的深度追问(最新推荐)

 更新时间:2025年12月04日 10:19:28   作者:旷野说  
作者通过一次调试经历,深入探讨了SpringSecurity的拦截机制,揭示了Filter与AOP在安全控制中的不同职,责,并分享了调试和理解框架的技巧,感兴趣的朋友跟随小编一起看看吧

🚨“为什么我的接口突然 403 了?”

🧩 一、那个让人抓狂的下午

上周三下午,我正和前端同事联调一个新功能。

他调用 /api/v1/orders/create 接口,返回:

{
  "status": 403,
  "message": "Access Denied"
}

“你是不是没给我开权限?”他问。

我皱眉:“不可能。我用的是管理员账号,Token 是刚登录拿的,而且本地跑得好好的。”

我打开 Postman 重试:

  • /login → 成功,返回 JWT;
  • /api/v1/profile → 成功,返回用户信息;
  • /api/v1/orders/create403,Access Denied

更诡异的是:断点根本没进 Controller
我甚至在 Controller 第一行打了日志,结果日志没输出。

“请求……根本没进来?”我喃喃自语。

那一刻,我意识到:

我的代码不是被业务逻辑拒绝的,而是被某一层“看不见的安全机制”提前拦截了。

而我对这层机制,几乎一无所知。

❓ 二、带着问题,向底层进发

我开始追问自己:

  • 请求到底是在哪被拦下的?
    • 是 Spring 的 AOP?还是更早的某个地方?
  • 为什么有些接口能通,有些不行?
    • 它们都在同一个 @RestController 里啊!
  • Spring Security 的 authorizeHttpRequests()@PreAuthorize 到底谁先生效?
    • 我的 JWT 解析 Filter,真的在权限校验前执行了吗?

这些问题,像一张密网,把我困在“配置能跑,但原理不清”的模糊地带。

于是,我决定:不再把 Spring Security 当成黑盒。我要搞清楚,从请求进来到被拦截,究竟发生了什么

🔍 三、真相的起点:Servlet Filter

经过翻源码、读文档、画流程图,我终于找到了答案的起点——

Spring Security 的安全拦截,根本不在 Spring 的 Bean 层,而是在更底层:Servlet 容器层。

换句话说:
你的请求,甚至还没到达 DispatcherServlet,就已经被一连串 Filter 检查过了。

而这一切,都基于 Java Web 最基础的机制:Servlet Filter

📦 四、什么是 Servlet Filter?

Filter 是 Java EE(现 Jakarta EE)标准的一部分,由 Tomcat、Jetty 等容器管理。

它能在 请求到达目标资源(如 Controller)前,或 响应返回前,对请求/响应进行拦截和处理。

核心方法就一个:

void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
  • 调用 chain.doFilter(...)放行,继续执行;
  • 不调用 → 拦截,直接返回(比如 403)。

⚠️ Filter 是链式执行的,顺序至关重要。

🧱 五、Spring Security 的核心:FilterChainProxy

Spring Security 并没有把十几个安全 Filter 直接注册到 Tomcat,而是把它们全部封装在一个特殊的 Filter 里FilterChainProxy

它像一个“安全中枢”,内部维护了一整条过滤器链:

graph LR
    A[HTTP Request] --> B[FilterChainProxy]
    B --> C[SecurityContextPersistenceFilter]
    B --> D[JwtAuthenticationFilter]     // 我们自定义的
    B --> E[ExceptionTranslationFilter]
    B --> F[FilterSecurityInterceptor]   // 最终权限校验!
    F --> G[DispatcherServlet → Controller]

💡 关键发现
我的 /orders/create 接口之所以 403,就是因为 FilterSecurityInterceptor 拦截了它——
而这时,我的 Controller 根本还没机会执行!

🔑 六、为什么/profile能过,/orders/create不行?

我检查了安全配置:

.authorizeHttpRequests(authz -> authz
    .requestMatchers("/login").permitAll()
    .anyRequest().authenticated()
)

看起来没问题啊?所有接口只要登录就能访问。

但后来我发现:我在 Service 层还加了 @PreAuthorize

@Service
public class OrderService {
    @PreAuthorize("hasRole('ADMIN')")
    public Order createOrder(OrderDto dto) { ... }
}

/profile 没有方法级注解。

真相大白

  • /profile:只经过 Filter 层(URL 权限),通过;
  • /orders/create:先过 Filter 层(通过),再进 AOP 层(方法权限),因无 ADMIN 角色被拒

但为什么没看到异常堆栈?

因为 ExceptionTranslationFilterAccessDeniedException 捕获后,静默转成了 403 响应——这正是 Spring Security 的“优雅”设计,也是调试的难点。

⚖️ 七、Filter vs AOP:职责分明

现在我终于理清了两者的分工:

机制作用层级典型用途是否依赖 Spring
Servlet FilterHTTP 请求层JWT 认证、CORS、日志、URL 权限❌ 不依赖(容器级)
Spring AOP方法调用层@PreAuthorize、事务、缓存✅ 依赖 Spring Bean

Spring Security = Filter(Web 安全) + AOP(方法安全)

  • Filter 拦请求:决定“你能不能访问这个 URL”;
  • AOP 拦方法:决定“你能不能调用这个方法”。

🧠 八、终极口诀:14 个字,牢牢记住

“Filter 拦请求,AOP 拦方法”
“Web 层用 Filter,服务层用 AOP”

  • 遇到 401/403 且 Controller 没执行? → 查 Filter 链(尤其是 FilterSecurityInterceptor)。
  • 遇到 方法被拒但 URL 能通? → 查 @PreAuthorize 和角色权限。

✅ 九、总结:从“能用”到“懂用”

这次 403 异常,像一记警钟,敲醒了我:

不要把框架当魔法。
只有理解底层机制,才能在问题发生时,一眼看穿本质。

现在,当我再看到 Spring Security 的配置:

.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
.sessionManagement().sessionCreationPolicy(STATELESS)
.authorizeHttpRequests(...).authenticated()

我不再觉得它只是“模板代码”,而是一个精密的安全流水线——每一步都有其不可替代的作用。

而那个下午的困惑,也成了我深入理解 Web 安全架构的起点。

📚 延伸建议

  • 调试技巧:在 FilterSecurityInterceptorMethodSecurityInterceptor 中打断点;
  • 日志增强:开启 logging.level.org.springframework.security=DEBUG
  • 安全测试:使用 Postman + 不同角色 Token 验证权限边界。

愿你下次再遇 403,不再慌张,而是微微一笑:

“哦,我知道你在哪拦我了。”

到此这篇关于一个开发者对 Spring Security 拦截机制的深度追问的文章就介绍到这了,更多相关Spring Security 拦截机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 关于log4j漏洞修复解决方案及源码编译

    关于log4j漏洞修复解决方案及源码编译

    Log4j 是Apache为Java提供的日志管理工具。他与System.out.println()的作用相似,用来跟踪、调试、维护程序。这篇文章主要介绍了关于log4j漏洞修复解决方案及源码编译,需要的朋友可以参考下
    2021-12-12
  • springboot + swagger 实例代码

    springboot + swagger 实例代码

    本篇文章主要介绍了springboot + swagger 实例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • JavaMail实现简单邮件发送

    JavaMail实现简单邮件发送

    这篇文章主要为大家详细介绍了JavaMail实现简单邮件发送,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • Java毕业设计之多用户宿舍管理系统的实现

    Java毕业设计之多用户宿舍管理系统的实现

    这篇文章主要介绍了基于Java实现的多用户宿舍管理系统,本文采用了jsp、servlet、jdbc等技术,文中示例代码讲解详细,需要的可以参考一下
    2022-02-02
  • Java基于Runtime调用外部程序出现阻塞的解决方法

    Java基于Runtime调用外部程序出现阻塞的解决方法

    这篇文章主要介绍了Java基于Runtime调用外部程序出现阻塞的解决方法,是一个非常实用的技巧,需要的朋友可以参考下
    2014-09-09
  • Java中的悲观锁与乐观锁是什么

    Java中的悲观锁与乐观锁是什么

    这篇文章主要介绍了Java中的悲观锁与乐观锁是什么,帮助大家更好的理解和学习Java锁的相关知识,感兴趣的朋友可以了解下
    2020-09-09
  • 动态配置Spring Boot日志级别的全步骤

    动态配置Spring Boot日志级别的全步骤

    这篇文章主要给大家介绍了关于动态配置Spring Boot日志级别的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Spring Boot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-04-04
  • 使用Java和SpringBoot实现服务器发送事件(Server-Sent Events)

    使用Java和SpringBoot实现服务器发送事件(Server-Sent Events)

    使用Java开发web应用,大多数时候我们提供的接口返回数据都是一次性完整返回,有些时候,我们也需要提供流式接口持续写出数据,以下提供一种简单的方式,本文给大家介绍了如何在Java web中实现服务器发送事件,需要的朋友可以参考下
    2024-02-02
  • RabbitMQ的安装和配置可视化界面的详细步骤

    RabbitMQ的安装和配置可视化界面的详细步骤

    这篇文章主要介绍了RabbitMQ的安装和配置可视化界面的详细步骤,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-06-06
  • 基于Java实现Excel列数据提取工具

    基于Java实现Excel列数据提取工具

    这篇文章主要介绍了一个使用Java语言开发的Excel列数据提取工具,该工具借助Apache POI库实现对Excel文件的读取与特定列数据提取功能,感兴趣的小伙伴可以跟随小编一起学习一下
    2025-06-06

最新评论