双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. 额外检查点
- 确保
jwtDecoderBean已正确配置,能解析合法的JWT令牌; - 若
/bo/**请求需要跨域,需确保第二个链配置了CORS或全局CORS规则生效; - 验证JWT中的
scope或authorities字段包含SCOPE_products.read权限标识。
内容的提问来源于stack exchange,提问作者habubacker
相关产品推荐
相关产品推荐

