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

双SecurityFilterChain配置异常:JWT资源服务链路失效求助

问题分析与解决

问题描述

配置了两个SecurityFilterChain:

  • 第一个匹配/api/**路径,使用UsernamePasswordAuthenticationFilter,运行正常;
  • 第二个匹配/bo/**路径,作为基于JWT的ResourceServer,无法正常工作。

现有配置代码

第一个过滤器链(Order 1)

@Bean
@Order(1)
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    CorsConfiguration corsConfiguration = new CorsConfiguration();
    corsConfiguration.setAllowedOrigins(Arrays.asList(WHITE_LIST_CORS_URL));
    corsConfiguration.setAllowedHeaders(List.of("Authorization", "Cache-Control", "Content-Type", "x-auth-token"));
    corsConfiguration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PUT", "OPTIONS", "PATCH", "DELETE"));
    corsConfiguration.setAllowCredentials(true);
    corsConfiguration.setMaxAge(3000L);
    corsConfiguration.setExposedHeaders(List.of("Authorization"));
    http.csrf(AbstractHttpConfigurer::disable).authorizeHttpRequests().antMatchers(WHITE_LIST_URL).permitAll()
        .antMatchers("/api/**").authenticated()
    .and().cors().configurationSource(request -> corsConfiguration).and()
    .csrf().disable().exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
    .sessionManagement(session -> session.sessionCreationPolicy(STATELESS))
    .authenticationProvider(authenticationProvider)
    .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class).headers()
    .frameOptions().sameOrigin();
    
    return http.build();
}

第二个过滤器链(Order 2)

@Bean
@Order(2)
SecurityFilterChain boSecurityFilterChain(HttpSecurity http) throws Exception {
    
     http.authorizeRequests()
         .antMatchers("/bo/**").access("hasAuthority('SCOPE_products.read')")
         .anyRequest().authenticated()
    .and().oauth2ResourceServer().jwt();
    return http.build();
}

核心问题

第一个SecurityFilterChain未指定请求匹配范围,会拦截所有请求(包括/bo/**)。由于它的@Order(1)优先级更高,第二个过滤器链根本无法被触发。同时第一个链的权限规则未覆盖/bo/**路径,会导致这类请求被第一个链直接拒绝,不符合预期的JWT认证逻辑。

解决步骤

1. 限定第一个过滤器链的处理范围

给第一个SecurityFilterChain添加requestMatchers,明确它只处理白名单和/api/**路径的请求,让/bo/**请求能流转到第二个链:

@Bean
@Order(1)
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    CorsConfiguration corsConfiguration = new CorsConfiguration();
    corsConfiguration.setAllowedOrigins(Arrays.asList(WHITE_LIST_CORS_URL));
    corsConfiguration.setAllowedHeaders(List.of("Authorization", "Cache-Control", "Content-Type", "x-auth-token"));
    corsConfiguration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH")); // 移除重复的请求方法
    corsConfiguration.setAllowCredentials(true);
    corsConfiguration.setMaxAge(3000L);
    corsConfiguration.setExposedHeaders(List.of("Authorization"));
    
    http
        .requestMatchers(matchers -> matchers.antMatchers(WHITE_LIST_URL, "/api/**")) // 新增:限定处理路径
        .csrf(AbstractHttpConfigurer::disable)
        .authorizeHttpRequests(auth -> auth
            .antMatchers(WHITE_LIST_URL).permitAll()
            .antMatchers("/api/**").authenticated()
        )
        .cors(cors -> cors.configurationSource(request -> corsConfiguration))
        .exceptionHandling(ex -> ex.authenticationEntryPoint(unauthorizedHandler))
        .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
        .authenticationProvider(authenticationProvider)
        .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
        .headers(headers -> headers.frameOptions(frame -> frame.sameOrigin()));
    
    return http.build();
}

2. 更新第二个过滤器链的API(可选,适配新版本)

authorizeRequests已被标记为过时,建议替换为authorizeHttpRequests,保持逻辑不变:

@Bean
@Order(2)
SecurityFilterChain boSecurityFilterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            .antMatchers("/bo/**").access("hasAuthority('SCOPE_products.read')")
            .anyRequest().authenticated()
        )
        .oauth2ResourceServer(oauth2 -> oauth2.jwt());
    
    return http.build();
}

3. 额外检查点

  • 确保jwtDecoder Bean已正确配置,能解析合法的JWT令牌;
  • 若/bo/**请求需要跨域,需确保第二个链配置了CORS或全局CORS规则生效;
  • 验证JWT中的scope或authorities字段包含SCOPE_products.read权限标识。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 15:45:10