Prevent Spring Boot from registering a servlet filter
Asked Answered
E

4

47

I have a Spring Boot WebMVC application, and a bean that inherits from AbstractPreAuthenticatedProcessingFilter which I am explicitly adding to a specific spot in the Spring Security filter chain. My Spring Security configuration looks like this:

<http pattern="/rest/**">
  <intercept-url pattern="/**" access="ROLE_USER"/>
  <http-basic/>
  <custom-filter after="BASIC_AUTH_FILTER" ref="preAuthenticationFilter"/>
</http>

<beans:bean id="preAuthenticationFilter" class="a.b.PreAuthenticationFilter">
  <beans:property name="authenticationManager" ref="customAuthenticationManager"/>
</beans:bean>

The security configuration works. The problem is, because the PreAuthenticationFilter class inherits from AbstractPreAuthenticatedProcessingFilter, Spring Boot treats it as a general purpose servlet filter and is adding it to the servlet filter chain for all requests. I don't want this filter to be part of the filter chain for all requests. I only want it to be part of the specific Spring Security filter chain that I've configured. Is there a way to prevent Spring Boot from automatically adding the preAuthenticationFilter bean to the filter chain?

Edrick answered 10/2, 2015 at 0:18 Comment(0)
K
66

By default Spring Boot creates a FilterRegistrationBean for every Filter in the application context for which a FilterRegistrationBean doesn't already exist. This allows you to take control of the registration process, including disabling registration, by declaring your own FilterRegistrationBean for the Filter. For your PreAuthenticationFilter the required configuration would look like this:

@Bean
public FilterRegistrationBean registration(PreAuthenticationFilter filter) {
    FilterRegistrationBean registration = new FilterRegistrationBean(filter);
    registration.setEnabled(false);
    return registration;
}

You may also be interested in this Spring Boot issue which discusses how to disable the automatic registration of Filter and Servlet beans.

Kezer answered 10/2, 2015 at 9:28 Comment(4)
filter working even after registration.setEnabled(false);Welldisposed
@Welldisposed In that case I'd recommend asking a question of your own with a minimal, complete, and verifiable example.Kezer
@Welldisposed what did you end up doing? I am facing same issue, even after setEnabled(false); filter is registering.Cargian
occur an error No qualifying bean of type 'XxxFilter' availableBlasting
S
11

If you want to unregister all filters at one time here's my trick:

public class DefaultFiltersBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory bf)
            throws BeansException {
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) bf;

        Arrays.stream(beanFactory.getBeanNamesForType(javax.servlet.Filter.class))
                .forEach(name -> {

                    BeanDefinition definition = BeanDefinitionBuilder
                            .genericBeanDefinition(FilterRegistrationBean.class)
                            .setScope(BeanDefinition.SCOPE_SINGLETON)
                            .addConstructorArgReference(name)
                            .addConstructorArgValue(new ServletRegistrationBean[]{})
                            .addPropertyValue("enabled", false)
                            .getBeanDefinition();

                    beanFactory.registerBeanDefinition(name + "FilterRegistrationBean",
                            definition);
                });
    }
}

A bit more about this technique - here.

Sense answered 28/11, 2015 at 2:45 Comment(1)
This has worked well in our app that declared a lot of Filter beans to be used elsewhere.Archambault
E
5

If you need to disable registering 2 filters(like i did), include a name for the bean(so that they do not override):

@Bean(name = "filterRegistrationBean1")
public FilterRegistrationBean<YourFilter1> registration(YourFilter1 f1) {
    FilterRegistrationBean<YourFilter1> registration = new FilterRegistrationBean<>(f1);
    registration.setEnabled(false);
    return registration;
}

@Bean(name = "filterRegistrationBean2")
public FilterRegistrationBean<YourFilter2> registration(YourFilter2 f2) {
    FilterRegistrationBean<YourFilter2> registration = new FilterRegistrationBean<>(f2);
    registration.setEnabled(false);
    return registration;
}

Bonus:

The fact that all filters internal to Spring Security are unknown to the container is important, especially in a Spring Boot application, where, by default, all @Beans of type Filter are registered automatically with the container. So if you want to add a custom filter to the security chain, you need to either not make it be a @Bean or wrap it in a FilterRegistrationBean that explicitly disables the container registration.

Elseelset answered 9/2, 2022 at 7:23 Comment(0)
B
0

I use aop to do that, use around pointcut to joincut your filter, manully invode
filterChain.doFilter(request, response)

@Aspect
@Component
public class AspectDemo {

    @Around(value = "com.xxx.pointcut01()")
    public void around01(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("[Aspect-around01] start");

        ServletRequest request = (ServletRequest)Arrays.asList(
                ((MethodInvocationProceedingJoinPoint) joinPoint).getArgs()
        ).get(0);

        ServletResponse response = (ServletResponse)Arrays.asList(
                ((MethodInvocationProceedingJoinPoint) joinPoint).getArgs()
        ).get(1);


        FilterChain filterChain = (FilterChain)Arrays.asList(
                ((MethodInvocationProceedingJoinPoint) joinPoint).getArgs()
        ).get(2);

        filterChain.doFilter(request, response);

        //do not execute origin doFilter() method
        //joinPoint.proceed();
        System.out.println("[Aspect-around01] end");

    }

}
Blasting answered 9/12, 2022 at 11:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.