Spring-boot: Provide an exclude URL pattern for FilterRegistrationBean

Created on 19 Nov 2016  路  8Comments  路  Source: spring-projects/spring-boot

FilterRegistrationBean has a setUrlPatterns for customizing the URL patterns that the filter will be registered against. Sometimes, setting exclusion pattern is desired more than inclusion pattern. For example, I want to be able to say _"Exclude all URLs that start with monitoring, thank you"_, vs. listing each endpoint that the service may support.
This ticket is to provide support for exclude URL patterns. If both exclude and include patterns exist, and there's a conflict, exclude should win as usually is the case. I understand that the matching is done by the servlet container but I'm still hoping that there's some way to do this.

declined

Most helpful comment

I found a way to do this. OncePerRequestFilter has a shouldNotFilter(HttpServletRequest request) method, so I could do:

@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
    return excludeUrlPatterns.stream()
        .anyMatch(p -> pathMatcher.match(p, request.getServletPath()));
}

where excludeUrlPatterns is a Collection<String> and pathMatcher is an AntPathMatcher.
The catch is that this happens _after_ the filter is applied using whatever pattern has been specified in the FilterRegistrationBean (or the default /*).

All 8 comments

I found a way to do this. OncePerRequestFilter has a shouldNotFilter(HttpServletRequest request) method, so I could do:

@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
    return excludeUrlPatterns.stream()
        .anyMatch(p -> pathMatcher.match(p, request.getServletPath()));
}

where excludeUrlPatterns is a Collection<String> and pathMatcher is an AntPathMatcher.
The catch is that this happens _after_ the filter is applied using whatever pattern has been specified in the FilterRegistrationBean (or the default /*).

Thanks for sharing your approach. I think something like that is your best option here as the Servlet API doesn't provide a way to configure URL pattern exclusions. You can only add inclusions.

The solution provided by @asarkar works perfect! Thanks!

Mind, you may still have to add the necessary variables to your method (or at class-level) Collection<String> excludeUrlPatterns = new ArrayList<>(); and initialize it like this: excludeUrlPatterns.add(AppConstants.API_BASE + "/auth/**"); as well as AntPathMatcher pathMatcher = new AntPathMatcher();.
I'm just adding this for people that are new to this technology or to developing in general (like me at the moment :) ).

can i use patterns like this:filterRegistrationBean.addUrlPatterns("/v1/*/member/*"); OR filterRegistrationBean.addUrlPatterns("/*/v1/member/*");to filter URLs like http://localhost:8080/v1/18682256/member/articles OR http://localhost:8080/18682256/v1/member/articles?

@mrCalmdow This issue is closed and we don't use the issue tracker for questions. The patterns work in the way that is described by the Servlet specification. If you need further help, please ask on Stack Overflow.

thanks for your answers.

Also could be done like this:

package br.com.actaholding.erpmiddleware.authorizer.filter;

@Configuration
public class CommonsRequestLoggingFilterConfig {

    private static final List<String> EXCLUDE_URL = Arrays.asList("/healthcheck", "/health-check");

    @Bean
    public CommonsRequestLoggingFilter logFilter() {

        CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter() {

            @Override
            protected boolean shouldNotFilter(HttpServletRequest request) {
                return EXCLUDE_URL.stream().anyMatch(exclude -> exclude.equalsIgnoreCase(request.getServletPath()));
            }
        };

        /*filter.set properties you need*/
        return filter;
    }
}

log4j2.xml

<Logger name="br.com.actaholding.erpmiddleware.authorizer.filter.CommonsRequestLoggingFilterConfig$1" level="${env:LOGGING_REQUEST_LEVEL:-INFO}">
            <AppenderRef ref="ConsoleAppender"/>
</Logger>

The '$1' after class name is because the anonymous / inner class.

Remember set env var 'LOGGING_REQUEST_LEVEL' to DEBUG

You could consider (probably shouldn't!) manually implementing the exclusion logic. Here's an spring boot example, not tested.

@Component
public class ExampleFilter implements Filter {

    @Value("${filter.url-exclusion-list}")
    private List<String> urlExclusionList;


    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;

        String requestUrl = httpServletRequest.getRequestURL().toString().toLowerCase();

        AtomicBoolean ignoreUrl = new AtomicBoolean(false);

        urlExclusionList.forEach((url) -> {
            if(requestUrl.contains(url.toLowerCase())){
                ignoreUrl.set(true);
            }
        });


        if(!ignoreUrl.get()){
            // "before" filter logic here
        }

        filterChain.doFilter(servletRequest, servletResponse);

        if(!ignoreUrl.get()){
            // "after" filter logic here
        }

    }
}
Was this page helpful?
0 / 5 - 0 ratings