You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Spring Security:如何让过滤器忽略WebSecurity配置的忽略URL?

解决Spring Security中WebSecurity忽略URL仍被自定义过滤器处理的问题

这个问题我之前也碰到过,核心原因在于WebSecurity的ignoring()规则和HttpSecurity中添加的过滤器的作用范围不是完全绑定的——或者说,你可能误解了web.ignoring()的生效逻辑,或者过滤器的注册方式导致它不受忽略规则约束。

先理清楚底层逻辑:web.ignoring()的作用是让匹配的请求完全跳过Spring Security的整个过滤器链,包括你通过addFilterAfter添加到HttpSecurity里的过滤器。如果你的忽略URL还是被过滤器处理了,大概率是下面两种情况之一:

  1. 你的正则匹配规则写得有问题,请求其实没被WebSecurity正确忽略;
  2. 过滤器的注册方式脱离了Spring Security的过滤器链(比如直接用@WebFilterFilterRegistrationBean注册到Servlet容器),这种情况下它不受Spring Security的忽略规则管控。

针对不同情况,这里有几种靠谱的解决方案:

方案一:在自定义过滤器中手动跳过忽略URL

这是最直接的方式,复用你原来的正则规则,在过滤器里判断请求是否属于忽略范围,是的话直接放行不处理。

修改你的MyFilter类,重写shouldNotFilter方法:

public class MyFilter extends OncePerRequestFilter {
    // 复用WebSecurity里的正则规则
    private static final Pattern IGNORED_URL_PATTERN = Pattern.compile("a regex pattern here");

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 你的核心过滤逻辑写在这里
        filterChain.doFilter(request, response);
    }

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
        String requestMethod = request.getMethod();
        String requestUri = request.getRequestURI();
        // 判断是否是POST请求且匹配忽略的URL正则
        return HttpMethod.POST.name().equalsIgnoreCase(requestMethod) 
                && IGNORED_URL_PATTERN.matcher(requestUri).matches();
    }
}

这个方法是OncePerRequestFilter提供的钩子,返回true时过滤器会跳过当前请求,完全符合你的需求。

方案二:通过HttpSecurity限制过滤器的作用范围

如果你的过滤器是通过HttpSecurity.addFilterAfter添加的,可以用NegatedRequestMatcher来反转忽略规则,让过滤器只对非忽略的URL生效:

@Override
protected void configure(HttpSecurity http) throws Exception {
    // 定义你要忽略的请求匹配器
    RequestMatcher ignoredMatcher = new RegexRequestMatcher("a regex pattern here", HttpMethod.POST.name());

    http
        // 让过滤器只作用于非忽略的请求
        .requestMatcher(new NegatedRequestMatcher(ignoredMatcher))
        .addFilterAfter(myFilter, AbstractPreAuthenticatedProcessingFilter.class)
        // 其他Spring Security配置...
        
        // 单独配置忽略URL的授权(允许匿名访问)
        .and()
        .requestMatcher(ignoredMatcher)
        .authorizeRequests()
        .anyRequest().permitAll();
}

这种方式把忽略规则和过滤器的作用范围绑定在一起,避免重复写正则规则。

方案三:如果是Servlet级过滤器,直接排除URL

如果你是用FilterRegistrationBean@WebFilter把过滤器注册到Servlet容器的(不是通过HttpSecurity添加),可以直接在注册时排除忽略的URL:

@Bean
public FilterRegistrationBean<MyFilter> myFilterRegistration(MyFilter myFilter) {
    FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();
    registrationBean.setFilter(myFilter);
    registrationBean.addUrlPatterns("/**"); // 匹配所有URL
    // 排除你要忽略的正则URL
    registrationBean.addExcludeUrlPatterns("a regex pattern here");
    return registrationBean;
}

注意这种方式是Servlet容器层面的过滤,和Spring Security的过滤器链是独立的,所以必须手动排除。

最后建议先检查你的正则匹配是否正确——比如用日志打印请求的URL和方法,确认是否真的匹配web.ignoring()里的规则,很多时候问题出在这里。

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

火山引擎 最新活动