Search code examples
javaspringspring-bootspring-securityspringfox

Disabling a filter for only a few paths


How do I get a filter to apply to every request off the root path except for ones I want to ignore? Here's my example:

I have a Spring Security filter like so:

private static class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .antMatcher("/**")
            .addFilterBefore(new AuthenticationFilter(), basicAuthenticationFilter.class);
    }

    @Override
    public void configure(WebSecurity web) {
        web
           .ignoring()
               .requestMatchers(SecurityServletRequestMatchers.servletIgnoreAuthMatcher());
    }
}

This filter populates a CustomApiToken object which contains all of our header information and puts it in the Spring Security context SecurityContextHolder.getContext().setAuthentication(token) for easy access to the token on the requesting controller.

I'm trying to add Springfox to the project, which means I want to disable the filter for the UI and API docs pages.

My original attempt was to add a clause to the method:

@Override
public void configure(HttpSecurity http) throws Exception {
    http
        .csrf().disable()
        .antMatcher("/**")
        .addFilterBefore(new AuthenticationFilter(), BasicAuthenticationFilter.class);

    http
        .requestMatcher(SecurityServletRequestMatchers.servletIgnoreAuthMatcher())
        .headers() //.servletIgnoreAuthMatchers has all the swagger urls also
            .defaultsDisabled()
            .disable()
        .authorizeRequests()
            .anyRequest().authenticated();
}

However I discovered that this only takes the second clause into account due to Spring Security only accepting the last clause.

I've since tried:

@Override
public void configure(HttpSecurity http) throws Exception {
    http
        .csrf().disable()
        .antMatcher("/**")
        .addFilterBefore(new AuthenticationFilter(), BasicAuthenticationFilter.class)
        .requestMatcher(SecurityServletRequestMatchers.servletIgnoreAuthMatcher())
        .headers()
            .defaultsDisabled()
            .disable()
        .authorizeRequests()
            .anyRequest().authenticated();
}

But that left the web filter on the Springfox URL giving me a missing authentication token error.

I've tried looking around here, and on the internet, but none of the examples have given me an acceptable response yet.


Solution

  • In your custom AuthenticationFilter you can define a RequestMatcher and use it before doing your logic, like so:

    public class AuthenticationFilter extends OncePerRequestFilter {
        private final RequestMatcher ignoredPaths = new AntPathRequestMatcher("/swagger-ui");
    
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {
            if (this.ignoredPaths.matches(request)) { 
                 filterChain.doFilter(request, response);
                 return;
            }
    
            // do your logic
            filterChain.doFilter(request, response);
        }
    }