Filter Invoke Twice When Register as Spring Bean

Filter invoke twice when register as Spring bean

As you have observed, Spring Boot will automatically register any bean that is a Filter with the servlet container. One option is to not expose your filter as a bean and only register it with Spring Security.

If you want to be able to autowire dependencies into your Filter then it needs to be a bean. That means you need to tell Spring Boot not to register it as a filter. As described in the documentation, you do that using a FilterRegistrationBean:

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

Spring Security Custom Filter gets called Multiple times

It's because Spring Boot picks up any Filter exposed as a @Bean and adds it to the ServletContext. By exposing it as a @Bean and by adding it to the Spring Security Filter Chain, you've effectively registered it twice.

Likely, you can simply remove the @Bean annotation from your authenticationFilter() method.

Custom filter gets called twice

Spring Boot will automatically register any Spring bean that extends Filter with the Servlet Container.

See Spring Boot documentation:

Registering Servlets, Filters, and Listeners as Spring Beans

Any Servlet, Filter, or servlet *Listener instance that is a Spring bean is registered with the embedded container.

Since your AppUserRegistrationFilter class is annotated with @Component, Spring will automatically create a singleton bean for the class, and it is therefore auto-registered with the Servlet container.

When you call http.addFilterAfter(new AppUserRegistrationFilter(appUserService), BearerTokenAuthenticationFilter.class);, you are manually creating another instance of the class, and manually registering the filter with the Servlet container.

Hence your code has registered two different instances of the class at the same time.

Solution: Don't call addFilterAfter() or remove the @Component annotation.

Spring boot filter called twice or not called at all

As a rule of thumb, don't add @Bean methods to @Component classes as those are handled differently than those in @Configuration classes. (See this).

The your code in the @Bean is too complex. Create and return a TomcatContextCustomizer to do the modification. Your code will lead to circulair references which will lead to initializing errors.

Add the following @Bean method to your @SpringBootApplication annotated class

@Bean
public TomactContextCustomizer cookieProcessorCustomizer() {
return (context) -> context.setCookieProcessor(new LegacyCookieProcessor());
}

Now in your Filter either remove the @Component or add an accompying FilterRegistrationBean to prevent it from being added to the regular chain of filters. (Spring Boot automatically registers all detected Filter instances to the regular filter chain).

@Bean
public FilterRegistrationBean<MyFilter> myFilterRegistrationBean(MyFilter myFilter) {
FilterRegistrationBean<MyFilter> frb = new FilterRegistrationBean<>(myFilter);
frb.setEnabled(false);
return frb;
}

If you remove @Component the above snippet isn't needed if you don't then you should reuse the scanned MyFilter instance in your security configuration.

@Configuration
public class AuthSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private MyFilter myFilter;

@Override
protected void configure(HttpSecurity http) throws Exception {

//configuring strategy
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.anyRequest().authenticated().and()
.oauth2ResourceServer().jwt().and();
http.csrf().disable();
http.addFilterBefore(myFilter, UsernamePasswordAuthenticationFilter.class);
http.exceptionHandling().authenticationEntryPoint(new AuthExceptionEntryPoint());
}

}

Register FilterRegistrationBean of same type twice

To register two filters of one type you will need to name them (or name at least one):

@Bean(name="filterRegistrationBean2")
public FilterRegistrationBean filterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(iamFilterBean2());
registration.setName("iamFilterBean2");

List<String> urlPatterns = new ArrayList<>();
urlPatterns.add("/api/external/auth");
registration.setUrlPatterns(urlPatterns);
return registration;
}

Save user after success authentication

By any chance is your filter annotated with @Component ? This could explain why it is called twice, as Spring Boot automatically registers any bean that is a Filter with the servlet container (see documentation).

So you can setup a registration bean to disable it :

@Bean
public FilterRegistrationBean<UserSavingFilter> disableUserSavingFilter(final UserSavingFilter filter) {
final FilterRegistrationBean<UserSavingFilter> filterRegistrationBean = new FilterRegistrationBean<>();
filterRegistrationBean.setFilter(filter);
filterRegistrationBean.setEnabled(false);
return filterRegistrationBean;
}

By default, custom filter beans without information of ordering are automatically added to the main servlet filter chain at the very last position (actually with the lowest precedence, as if you would apply default order annotation @Order(Ordered.LOWEST_PRECEDENCE), see Order).

In debug level you should see in the logs the position of the filters when they are added to the chain, something like :

... at position 4 of 4 in additional filter chain; firing Filter:
UserSavingFilter

About your second problem, if you are sure the user is actually saved (i.e. you find it into the database afterwards) then indeed it may just be because your getAll() method gets executed before your future call is completed.



Related Topics



Leave a reply



Submit