一个开发者对 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 拦截机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • springBoot静态资源加载不到,并且配置了也不生效问题及解决

    springBoot静态资源加载不到,并且配置了也不生效问题及解决

    这篇文章总结了一个在Spring Boot 2.6.x版本中,由于路径匹配策略改变导致静态资源无法加载的问题,并提供了解决方案:通过配置类或在配置文件中设置路径匹配策略为AntPathMatcher,或者直接降级Spring Boot版本
    2025-02-02
  • 详解Springboot整合Dubbo之代码集成和发布

    详解Springboot整合Dubbo之代码集成和发布

    本篇文章主要介绍了Springboot整合Dubbo之代码集成和发布,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-12-12
  • Mybatis实现动态增删改查功能的示例代码

    Mybatis实现动态增删改查功能的示例代码

    这篇文章主要介绍了Mybatis实现动态增删改查功能的示例代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-04-04
  • Java编码算法与哈希算法深入分析使用方法

    Java编码算法与哈希算法深入分析使用方法

    首先,我们一起来学习一下编码算法,举例说明,ASCII码就是我们常见的一种编码,字母a的编码是十六进制的0x61,字母b是0x62,以此类推。哈希算法,可被称为摘要算法。因此,哈希算法的加密是单向的,不可用密文解密得到明文
    2022-11-11
  • MybatisPlus实现数据拦截的使用示例

    MybatisPlus实现数据拦截的使用示例

    在MyBatis-Plus中,可以通过自定义拦截器来实现对SQL语句的拦截和修改,本文就来介绍一下如何使用,具有一定的参考价值,感兴趣的可以了解一下
    2023-10-10
  • Spring Boot源码实现StopWatch优雅统计耗时

    Spring Boot源码实现StopWatch优雅统计耗时

    这篇文章主要为大家介绍了Spring Boot源码实现StopWatch优雅统计耗时,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • 一篇文章带你解决 IDEA 每次新建项目 maven home directory 总是改变的问题

    一篇文章带你解决 IDEA 每次新建项目 maven home directory 总是改变的问题

    这篇文章主要介绍了一篇文章带你解决 IDEA 每次新建项目 maven home directory 总是改变的问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • Java多线程之火车售票系统

    Java多线程之火车售票系统

    这篇文章主要为大家详细介绍了Java多线程之火车售票系统,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-07-07
  • Java注解机制之Spring自动装配实现原理详解

    Java注解机制之Spring自动装配实现原理详解

    这篇文章主要为大家详细介绍了Java注解机制之Spring自动装配实现原理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-10-10
  • 详解Java常用工具类—泛型

    详解Java常用工具类—泛型

    这篇文章主要介绍了Java常用工具类—泛型,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03

最新评论