You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多SecurityFilterChain循环创建:多租户配置实现咨询

多租户独立SecurityFilterChain实现方案

核心实现步骤

1. 定义租户配置类

通过配置绑定读取租户的OAuth2 issuer信息:

@ConfigurationProperties(prefix = "tenants")
public class TenantSecurityProperties {
    // key: 租户名称,value: 对应OAuth2 issuer地址
    private Map<String, String> oauth2;

    // Getter & Setter
    public Map<String, String> getOauth2() {
        return oauth2;
    }

    public void setOauth2(Map<String, String> oauth2) {
        this.oauth2 = oauth2;
    }
}

2. 编写多租户Security配置类

直接通过@Bean方法批量生成每个租户的独立SecurityFilterChain,无需自定义factoryMethod:

@Configuration
@EnableWebSecurity
@EnableConfigurationProperties(TenantSecurityProperties.class)
public class MultiTenantSecurityConfig {

    private final TenantSecurityProperties tenantProps;
    private final ClientRegistrationRepository clientRegistrationRepo;
    private final OAuth2AuthorizedClientService authorizedClientService;

    // 构造注入依赖
    public MultiTenantSecurityConfig(TenantSecurityProperties tenantProps,
                                     ClientRegistrationRepository clientRegistrationRepo,
                                     OAuth2AuthorizedClientService authorizedClientService) {
        this.tenantProps = tenantProps;
        this.clientRegistrationRepo = clientRegistrationRepo;
        this.authorizedClientService = authorizedClientService;
    }

    @Bean
    public List<SecurityFilterChain> tenantSecurityFilterChains(HttpSecurity http) throws Exception {
        List<SecurityFilterChain> filterChains = new ArrayList<>();
        int chainOrder = 1; // 优先级:数字越小,匹配优先级越高

        // 遍历每个租户,生成对应的SecurityFilterChain
        for (Map.Entry<String, String> tenantEntry : tenantProps.getOauth2().entrySet()) {
            String tenantName = tenantEntry.getKey();
            String issuerUri = tenantEntry.getValue();

            // 复制HttpSecurity实例,避免多租户配置互相污染
            HttpSecurity tenantHttp = http.copyWithDefaults();

            filterChains.add(
                tenantHttp
                    // 设置根路径匹配器:仅处理该租户的路径请求
                    .securityMatcher("/" + tenantName + "/**")
                    // 配置授权规则
                    .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
                    // 配置OAuth2登录(根据需求可选)
                    .oauth2Login(oauth2 -> oauth2
                        .clientRegistrationRepository(clientRegistrationRepo)
                        .authorizedClientService(authorizedClientService)
                        .authorizationEndpoint(endpoint -> endpoint
                            .baseUri("/" + tenantName + "/oauth2/authorization"))
                        .redirectionEndpoint(endpoint -> endpoint
                            .baseUri("/" + tenantName + "/login/oauth2/code/*")))
                    // 配置OAuth2资源服务器(JWT模式)
                    .oauth2ResourceServer(rs -> rs.jwt(jwt -> jwt.issuerUri(issuerUri)))
                    // 设置会话策略(按需配置)
                    .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                    // 设置当前链的优先级
                    .order(chainOrder++)
                    .build()
            );
        }

        // 兜底规则:处理非租户路径(按需配置,比如直接拒绝访问)
        filterChains.add(
            http
                .securityMatcher("/**")
                .authorizeHttpRequests(auth -> auth.anyRequest().denyAll())
                .order(Integer.MAX_VALUE)
                .build()
        );

        return filterChains;
    }
}

关键细节说明

  • 避免配置污染:使用HttpSecurity.copyWithDefaults()创建独立的HttpSecurity实例,每个租户的配置都是隔离的,不会出现复用实例导致的匹配器层级问题,所有配置的securityMatcher都是根级别,仅匹配对应租户的路径。
  • 自动注册Bean:Spring会自动将@Bean方法返回的List<SecurityFilterChain>中的每个元素注册为独立的Bean,完全符合Spring Security的运行机制——框架会自动扫描所有SecurityFilterChain Bean,按order排序后匹配请求。
  • 优先级控制:通过order()方法设置每个租户链的优先级,确保租户路径优先被对应的规则处理,兜底链设置最高的Integer.MAX_VALUE,最后执行。

内容的提问来源于stack exchange,提问作者Cezary

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 08:13:19