Spring Security基于Customizer 的分布式权限配置最佳实践指南

 更新时间:2025年12月26日 10:52:05   作者:czlczl20020925  
本文介绍了如何通过引入“插拔式”设计模式来解决SpringSecurity开发中的痛点,包括调度中心、标准协议和业务实现三个部分,并详细介绍了这个机制的工作原理、优点和注意事项,感兴趣的朋友跟随小编一起看看吧

一、 背景与痛点

在传统的 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
@Resource
private List<AuthorizeRequestsCustomizer> authorizeRequestsCustomizers;
@Bean
protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
    httpSecurity
        // ... 其他配置 ...
        .authorizeHttpRequests(c -> {
            // 2. 核心逻辑:遍历所有注入的 Customizer,让它们自己定义规则
            authorizeRequestsCustomizers.forEach(customizer -> customizer.customize(c));
            // 3. 兜底规则(最后执行)
            c.anyRequest().authenticated();
        });
    return httpSecurity.build();
}

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

2. 标准协议:AuthorizeRequestsCustomizer

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

public abstract class AuthorizeRequestsCustomizer
        implements Customizer<AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry>, Ordered {
    @Resource
    private WebProperties webProperties;
    // 提供通用方法的封装,避免各模块硬编码前缀
    protected String buildAdminApi(String url) {
        return webProperties.getAdminApi().getPrefix() + url;
    }
    protected String buildAppApi(String url) {
        return webProperties.getAppApi().getPrefix() + url;
    }
    // 默认优先级,业务模块可以通过重写此方法调整自己在过滤器链中的位置
    @Override
    public int getOrder() {
        return 0;
    }
}

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

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

@Configuration
public class InfraSecurityConfiguration {
    @Bean("infraAuthorizeRequestsCustomizer")
    public AuthorizeRequestsCustomizer infraAuthorizeRequestsCustomizer() {
        return new AuthorizeRequestsCustomizer() {
            @Override
            public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) {
                // 定义该模块独有的权限规则
                registry.requestMatchers(buildAdminApi("/infra/file/**")).permitAll() // 文件下载免登录
                        .requestMatchers("/swagger-ui/**").permitAll() // Swagger 免登录
                        .requestMatchers("/druid/**").hasRole("ADMIN"); // 数据库监控需管理员
            }
            // 可选:如果需要在其他规则之前生效,可以调高优先级
            @Override
            public int getOrder() {
                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 进行顺序管理至关重要。

到此这篇关于Spring Security 进阶:基于 Customizer 的分布式权限配置架构设计的文章就介绍到这了,更多相关Spring Security Customizer分布式权限配置内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详细谈谈Spring事务是如何管理的

    详细谈谈Spring事务是如何管理的

    在使用传统的事务编程策略时,程序代码必然和具体的事务操作代码耦合,而使用Spring事务管理策略恰好可以避免这种尴尬,Spring的事务管理提供了两种方式:编程式事务管理和声明式事务管理,这篇文章主要给大家介绍了关于Spring事务是如何管理的相关资料,需要的朋友可以参考下
    2021-09-09
  • Spring框架中Bean的三种配置和实例化方法总结

    Spring框架中Bean的三种配置和实例化方法总结

    在Spring框架中,Bean的配置和实例化是很重要的基础内容,掌握各种配置方式,才能灵活管理Bean对象,本文将全面介绍Bean的别名配置、作用范围配置,以及构造器实例化、工厂实例化等方式
    2023-10-10
  • Java利用EasyExcel实现合并单元格

    Java利用EasyExcel实现合并单元格

    在某些业务场景中可能会有合并单元格的需求,本文将详细为大家讲解Java如何利用EasyExcel实现合并单元格,感兴趣的小伙伴可以了解一下
    2022-06-06
  • java fastJson转JSON两种常见的转义操作

    java fastJson转JSON两种常见的转义操作

    在实际开发中,我们有时需要将特殊字符进行转义,本文主要介绍了java fastJson转JSON两种常见的转义操作,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03
  • 一文详解Java线程的6种状态与生命周期

    一文详解Java线程的6种状态与生命周期

    一个线程在给定的时间点只能处于一种状态。线程可以有6种状态:New、Runnable、Blocked、Waiting、Timed waiting和Terminated。本文将详细讲解这6种状态,需要的可以参考一下
    2022-05-05
  • JAVA中的字符串常量池使用操作代码

    JAVA中的字符串常量池使用操作代码

    Java中的字符串常量池是Java堆中的一块特殊存储区域,用于存储字符串。它的实现是为了提高字符串操作的性能并节省内存,这篇文章主要介绍了JAVA中的字符串常量池,需要的朋友可以参考下
    2022-12-12
  • Java聊天室之实现客户端群聊功能

    Java聊天室之实现客户端群聊功能

    这篇文章主要为大家详细介绍了Java简易聊天室之实现客户端群聊功能,文中的示例代码讲解详细,具有一定的借鉴价值,需要的可以了解一下
    2022-10-10
  • Java使用jxl包写Excel文件适合列宽实现

    Java使用jxl包写Excel文件适合列宽实现

    用jxl.jar包,读写过Excel文件。也没有注意最适合列宽的问题,但是jxl.jar没有提供最适合列宽的功能,上次用到写了一下,可以基本实现最适合列宽。
    2013-11-11
  • Spring中Cache的使用方法详解

    Spring中Cache的使用方法详解

    这篇文章主要介绍了Spring中Cache的使用方法详解,Spring Cache 是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能,Spring Cache 提供了一层抽象,底层可以切换不同的缓存实现,需要的朋友可以参考下
    2024-01-01
  • java使用xstream实现xml文件和对象之间的相互转换

    java使用xstream实现xml文件和对象之间的相互转换

    xml是一个用途比较广泛的文件类型,在java里也自带解析xml的包,但是本文使用的是xstream来实现xml和对象之间的相互转换,xstream是一个第三方开源框架,使用起来比较方便,对java xml和对象转换相关知识感兴趣的朋友一起看看吧
    2023-09-09

最新评论