当前位置: 首页 > news >正文

Spring Security 进阶:基于 Customizer 的分布式权限配置架构设计

一、 背景与痛点

在传统的 Spring Security 开发中(尤其是单体大应用),我们往往会在一个主配置类(如SecurityConfig)里写死所有的 URL 权限规则:

// 传统写法:随着业务增长,这个方法会变成几百行的“面条代码”http.authorizeHttpRequests().requestMatchers("/admin/**").hasRole("ADMIN").requestMatchers("/order/**").hasRole("USER").requestMatchers("/pay/**").permitAll()// ... 无休止的追加 ...

痛点

  1. 严重耦合:基础架构层必须感知所有业务模块的 URL 规则。
  2. 维护困难:多人开发时,大家都在修改同一个文件,代码冲突不断。
  3. 扩展性差:新增一个业务模块,必须去改主工程的代码。

二、 核心架构设计

为了解决上述问题,我们引入了“插拔式”的设计模式。核心由三个部分组成:

  1. 调度中心:主配置类(只负责调度,不负责具体规则)。
  2. 标准协议AuthorizeRequestsCustomizer抽象类(定义怎么配)。
  3. 业务实现:各模块的 Customizer(具体配什么)。

1. 调度中心:主 SecurityFilterChain

在主配置类(如YudaoWebSecurityConfigurerAdapter)中,我们不再硬编码规则,而是利用 Spring 的自动注入(Dependency Injection)特性。

// 1. 注入所有实现了 Customizer 接口的 Bean@ResourceprivateList<AuthorizeRequestsCustomizer>authorizeRequestsCustomizers;@BeanprotectedSecurityFilterChainfilterChain(HttpSecurityhttpSecurity)throwsException{httpSecurity// ... 其他配置 ....authorizeHttpRequests(c->{// 2. 核心逻辑:遍历所有注入的 Customizer,让它们自己定义规则authorizeRequestsCustomizers.forEach(customizer->customizer.customize(c));// 3. 兜底规则(最后执行)c.anyRequest().authenticated();});returnhttpSecurity.build();}

解析:主配置类变成了一个“容器”,它根本不知道/order需要什么权限,它只负责把话筒交给各个业务模块,让模块自己“发言”。

2. 标准协议:AuthorizeRequestsCustomizer

我们需要定义一个抽象类,既作为统一的接口类型,又可以提供一些通用的工具方法(如 API 前缀处理)。

publicabstractclassAuthorizeRequestsCustomizerimplementsCustomizer<AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry>,Ordered{@ResourceprivateWebPropertieswebProperties;// 提供通用方法的封装,避免各模块硬编码前缀protectedStringbuildAdminApi(Stringurl){returnwebProperties.getAdminApi().getPrefix()+url;}protectedStringbuildAppApi(Stringurl){returnwebProperties.getAppApi().getPrefix()+url;}// 默认优先级,业务模块可以通过重写此方法调整自己在过滤器链中的位置@OverridepublicintgetOrder(){return0;}}

3. 业务实现:模块化的 Customizer

假设我们有一个“基础设施模块 (Infra)”,它需要开放 Swagger 文档和一些监控断点,我们不需要改主工程,只需在 Infra 模块内部写一个 Bean:

@ConfigurationpublicclassInfraSecurityConfiguration{@Bean("infraAuthorizeRequestsCustomizer")publicAuthorizeRequestsCustomizerinfraAuthorizeRequestsCustomizer(){returnnewAuthorizeRequestsCustomizer(){@Overridepublicvoidcustomize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry){// 定义该模块独有的权限规则registry.requestMatchers(buildAdminApi("/infra/file/**")).permitAll()// 文件下载免登录.requestMatchers("/swagger-ui/**").permitAll()// Swagger 免登录.requestMatchers("/druid/**").hasRole("ADMIN");// 数据库监控需管理员}// 可选:如果需要在其他规则之前生效,可以调高优先级@OverridepublicintgetOrder(){return-10;}};}}

三、 工作原理深度解析

这个机制之所以能工作,依赖于 Spring 容器强大的生命周期管理:

  1. 启动扫描 (Scanning)
    Spring Boot 启动时,扫描所有加了@Configuration的类。
  2. Bean 注册 (Registration)
    各个业务模块(Infra, Order, Pay)定义的AuthorizeRequestsCustomizer被实例化并注册到 Spring 容器中。
  3. 依赖收集 (Collection)
    当初始化主配置类YudaoWebSecurityConfigurerAdapter时,@Resource private List<AuthorizeRequestsCustomizer> list这行代码会触发 Spring 去容器里查找所有类型为AuthorizeRequestsCustomizer的 Bean,并将它们装进一个 List 集合中。
  4. 规则应用 (Application)
    在构建SecurityFilterChain时,代码遍历这个 List,依次调用customize()方法。
  5. 最终生效 (Finalization)
    Spring Security 将这些分散定义的规则合并成一个完整的RequestMatcher链条。

四、 优缺点总结

优点

  • 开闭原则 (Open/Closed Principle):对扩展开放(新增模块只需加新 Bean),对修改关闭(无需动主配置)。
  • 高内聚:业务模块的权限规则写在业务模块内部,代码物理距离更近,更容易理解。
  • 灵活性:通过Ordered接口,可以精确控制规则的生效顺序(例如:通用黑名单规则优先级最高,普通业务规则优先级居中,兜底规则优先级最低)。

注意事项

  • 顺序问题:Spring Security 的匹配原则是“先匹配生效(First Match Wins)”。如果一个优先级高的 Customizer 配置了/**->permitAll,那么后面所有模块的规则都会失效。因此使用Ordered进行顺序管理至关重要。
http://www.jsqmd.com/news/130422/

相关文章:

  • SSH会话管理实战:识别与清理非法连接的完整指南
  • 邦芒干货:三点让你体面离职
  • 【护理学专业论文写作模版】基于中西医结合与多学科协作的上消化道出血护理模式:消化性溃疡患者全程管理策略研究
  • 1X Technologies推出Home Collection生活周边!以柔软美学重塑家用机器人品牌,降低消费者接受门槛
  • AI狂奔之下的伦理拷问:在创新与规范之间寻找平衡
  • AI全景之第五章第五节:图神经网络(GNN)与几何深度学习
  • TOSHIBA TC4053BFT(EL,N) TSSOP16 模拟开关/多路复用器
  • 体重电子秤MCU芯片方案
  • AI“好产品”的年度答案,2025年度凌云奖即将揭晓
  • 数据结构实战:从复杂度到C++实现
  • 数据安全新选择:访答本地知识库
  • AI全景之第六章第一节:语言模型演进
  • C#(更新中)
  • 解析 ‘Command Pattern’:实现具备‘完美撤销’(Undo)功能的游戏指令引擎
  • 瀚德凯尔座椅电梯提供租赁体验服务吗? - TIMWORKROOM
  • 拆解Mate X7的“超可靠折叠玄武架构”:从内到外全身都很“硬”!
  • 完整教程:深度学习理论与实战:MNIST 手写数字分类实战
  • 为什么不让程序员直接对接客户?而是通过产品经理…
  • 横河 AQ6370D 光谱分析仪
  • [BUUOJ 护网杯 2018 ] easy_tornado 题解
  • DataWorks 又又又升级了,这次我们通过 Arrow 列存格式让数据同步速度提升10倍!
  • Java计算机毕设之基于SpringBoot+Vue实现的前后端分离的高校毕业设计选题系基于SpringBoot和Vue的毕业设计选题管理系统的设计与实现(完整前后端代码+说明文档+LW,调试定制等)
  • 4453
  • 什么是 ‘Type Erasure’ (类型擦除)?对比 `std::any` 与虚函数在解耦方面的异同
  • AI浪潮下,文化原创力的坚守与重塑
  • 软件的白盒测试(一)
  • 2025年电缆生产厂家排名:天津电缆生产厂家推荐,知名的电缆生产厂家推荐(12月TOP榜单) - 品牌2026
  • 大数据隐私保护技术全解析:脱敏、匿名化、差分隐私哪个更实用?
  • .NET 进阶 —— 深入理解线程(3)ThreadPool 与 Task 入门:从手动线程到池化任务的升级
  • 第六十四篇