Spring Boot中permitAll失效:允许访问的端点触发CustomOncePerRequestFilter
当你通过addFilterBefore把自定义过滤器加入Spring Security过滤器链时,所有进入应用的请求都会先经过这个过滤器,后续配置的permitAll()授权规则不会提前拦截过滤器的执行。因为Spring Security的执行顺序是:过滤器链先处理请求,之后才会进行授权决策(比如判断是否需要认证、是否允许访问)。所以即便你设置了/content/**允许匿名访问,自定义过滤器依然会被触发。
有两种常用解决方式,可根据你的实际需求选择:
方案1:在自定义过滤器内跳过指定路径处理
修改CustomOncePerRequestFilter的doFilterInternal方法,先判断请求路径是否属于permitAll范围,若是则直接放行,不执行后续过滤逻辑:
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String requestURI = request.getRequestURI(); // 匹配需要跳过的路径 if (requestURI.startsWith("/art/") || requestURI.startsWith("/content/")) { filterChain.doFilter(request, response); return; } // 原有的过滤器业务逻辑 // ... }
方案2:通过WebSecurity忽略指定路径的Spring Security过滤
在SecurityConfiguration中添加WebSecurityCustomizer Bean,将/art/**和/content/**排除在Spring Security过滤器链之外。这种方式下,这些路径不会经过任何Spring Security过滤器(包括你的自定义过滤器和默认认证过滤器):
@Configuration @EnableWebSecurity public class SecurityConfiguration { @Autowired private CustomOncePerRequestFilter tokenFilter; @Bean protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeHttpRequests(auth -> auth .antMatchers("/api/contenteditor/feed/**").hasAnyRole("SITE_ADMIN", "STANDARD_ADMIN", "DOMAIN_MEMBER") .anyRequest().authenticated()) .addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class) .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); // CORS配置保持不变 CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(Arrays.asList("*")); configuration.setAllowedMethods(Arrays.asList("*")); configuration.setAllowedHeaders(Arrays.asList("*")); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); http.cors().configurationSource(source); return http.build(); } @Bean public WebSecurityCustomizer webSecurityCustomizer() { return web -> web.ignoring() .antMatchers("/art/**", "/content/**"); } }
注意:使用
web.ignoring()后,这些路径的请求不会经过Spring Security的任何处理,包括CORS。如果这些路径需要CORS支持,你需要确保CORS过滤器在Spring Security过滤器之前执行,或者通过@CrossOrigin注解单独配置。
额外优化提示
原代码中连续调用了两次authorizeHttpRequests(),可以合并为一个链式调用,让配置更简洁(不影响功能,仅提升可读性),如方案2中的写法。
内容的提问来源于stack exchange,提问作者Harsh Kanakhara

