Spring Security 6多过滤器链配置问题:UI与REST认证冲突
问题排查与解决方案
1. 精准配置过滤器链的RequestMatcher
这是核心问题——API链优先级更高(Order=1),如果它的RequestMatcher未精准限定URL范围,会拦截所有请求包括UI路径。必须给每个链明确指定匹配规则:
API过滤器链配置
@Bean @Order(1) public SecurityFilterChain apiSecurityFilterChain(HttpSecurity http) throws Exception { http // 仅匹配API前缀路径,比如/api/** .requestMatcher(new AntPathRequestMatcher("/api/**")) .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) // 添加REST专属认证过滤器,放在Spring默认过滤器之前 .addFilterBefore(customApiAuthFilter(), UsernamePasswordAuthenticationFilter.class) // 禁用UI相关配置(表单登录、CSRF) .formLogin(form -> form.disable()) .csrf(csrf -> csrf.disable()) // 配置API专属的认证异常处理,返回JSON响应 .exceptionHandling(ex -> ex .authenticationEntryPoint((request, response, authException) -> { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.setContentType(MediaType.APPLICATION_JSON_VALUE); // 写入自定义错误JSON内容 }) ); return http.build(); }
UI过滤器链配置
@Bean @Order(2) public SecurityFilterChain uiSecurityFilterChain(HttpSecurity http) throws Exception { http // 匹配UI路径,或排除API路径的所有请求 .requestMatcher(new AntPathRequestMatcher("/api/**").negate()) .authorizeHttpRequests(auth -> auth .requestMatchers("/app/login").permitAll() .anyRequest().authenticated() ) .formLogin(form -> form .loginPage("/app/login") .loginProcessingUrl("/app/login") .defaultSuccessUrl("/app/dashboard") .permitAll() ) // UI启用CSRF保护 .csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())) .logout(logout -> logout .logoutUrl("/app/logout") .logoutSuccessUrl("/app/login?logout") .permitAll() ); return http.build(); }
2. 隔离REST认证过滤器的配置
单独API链正常、同时启用失败,大概率是过滤器在UI链中被错误执行,或认证逻辑冲突:
- 不要给自定义
UsernamePasswordAuthenticationFilter加@Component注解,只在API链中手动实例化 - 给过滤器设置专属的API登录路径,避免和UI路径冲突:
private UsernamePasswordAuthenticationFilter customApiAuthFilter(AuthenticationManager apiAuthManager) { UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter(); filter.setFilterProcessesUrl("/api/login"); filter.setAuthenticationManager(apiAuthManager); // 配置API专属的认证成功/失败处理器 filter.setAuthenticationSuccessHandler((request, response, auth) -> { response.setStatus(HttpServletResponse.SC_OK); response.setContentType(MediaType.APPLICATION_JSON_VALUE); // 返回认证成功JSON }); filter.setAuthenticationFailureHandler((request, response, ex) -> { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.setContentType(MediaType.APPLICATION_JSON_VALUE); // 返回认证失败JSON }); return filter; } // 为API链单独配置AuthenticationManager @Bean public AuthenticationManager apiAuthenticationManager(AuthenticationConfiguration config) throws Exception { return config.getAuthenticationManager(); }
3. 调试请求匹配逻辑
开启Spring Security调试日志,确认请求匹配的过滤器链:
在application.properties中添加:
logging.level.org.springframework.security.web.FilterChainProxy=DEBUG
日志会显示类似Matching RequestMatcher Ant [pattern='/api/**'] for request GET /app/login的内容,可直接定位请求匹配错误的问题。
4. 排除静态资源拦截
如果有UI静态资源(CSS/JS等),在UI链中添加允许规则:
.requestMatchers("/static/**", "/css/**", "/js/**").permitAll()
内容的提问来源于stack exchange,提问作者Daniel Cosio
相关产品推荐
相关产品推荐

