如何配置Spring Security(Spring 6)让过滤器不执行在未受保护路由上?
问题:Spring Boot 3中如何让Security过滤器仅作用于受保护端点
我有一个Spring Boot 3应用,包含两个端点:/secured-api(需要认证)和/public/open-api(公开访问)。当前配置的自定义过滤器MyFilter会被所有请求触发,包括公开端点的请求,但我希望它只在访问受保护端点时才执行。
控制器代码
@RestController public class TestController { @GetMapping("/secured-api") public String securedApi() { return "secured"; } @GetMapping("/public/open-api") public String openApi() { return "open"; } }
当前安全配置
@Configuration public class ComponentSecurityContext { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { return http .addFilterAt(new MyFilter(), BasicAuthenticationFilter.class) .authorizeHttpRequests(customizer -> customizer .requestMatchers(new AntPathRequestMatcher("/public/**")) .permitAll() .anyRequest() .authenticated()) .build(); } public static class MyFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { System.out.println("Filter is called for uri: " + request.getRequestURI()); // JWT令牌验证逻辑,无效/过期会抛出异常 filterChain.doFilter(request, response); } } }
当前现象
执行以下请求:
curl http://localhost:9003/public/open-api curl http://localhost:9003/secured-api
两个端点都会触发过滤器:
Filter is called for uri: /public/open-api Filter is called for uri: /secured-api
需求:让MyFilter仅对受保护的端点生效,公开端点请求不会触发该过滤器。
解决方案(Spring Boot 3/Spring 6适配)
方式一:在过滤器内部跳过公开路径
修改MyFilter,重写shouldNotFilter方法,指定不需要过滤的路径:
public static class MyFilter extends OncePerRequestFilter { private final AntPathMatcher pathMatcher = new AntPathMatcher(); @Override protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException { // 指定公开路径,这些路径不执行过滤器逻辑 return pathMatcher.match("/public/**", request.getRequestURI()); } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { System.out.println("Filter is called for uri: " + request.getRequestURI()); // JWT令牌验证逻辑 filterChain.doFilter(request, response); } }
这种方式简单直接,无需改动SecurityFilterChain配置,适合过滤器逻辑仅需针对特定路径跳过的场景。
方式二:拆分SecurityFilterChain,为不同路径配置不同过滤器链
创建两个独立的SecurityFilterChain,分别处理公开路径和受保护路径:
@Configuration public class ComponentSecurityContext { // 公开路径的过滤器链:无自定义过滤器,直接放行 @Bean @Order(1) public SecurityFilterChain publicSecurityFilterChain(HttpSecurity http) throws Exception { return http .securityMatcher("/public/**") .authorizeHttpRequests(auth -> auth.anyRequest().permitAll()) .build(); } // 受保护路径的过滤器链:添加自定义过滤器,要求认证 @Bean @Order(2) public SecurityFilterChain securedSecurityFilterChain(HttpSecurity http) throws Exception { return http .securityMatcher("/secured-api") .addFilterAt(new MyFilter(), BasicAuthenticationFilter.class) .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) .build(); } public static class MyFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { System.out.println("Filter is called for uri: " + request.getRequestURI()); // JWT令牌验证逻辑 filterChain.doFilter(request, response); } } }
通过@Order指定链的执行顺序,securityMatcher限定每个链处理的路径。公开路径的链不会加载自定义过滤器,只有受保护路径的链才会触发MyFilter。
注意:
securityMatcher是Spring 6引入的API,替代了旧版本的antMatcher,能更清晰地划分不同过滤器链的作用范围。
内容的提问来源于stack exchange,提问作者Gabriel Dinant
相关产品推荐
相关产品推荐

