Understanding Spring Security’s Core FilterChainProxy and Adding Custom Filters

This article explains how Spring Security builds its core FilterChainProxy and DefaultSecurityFilterChain, outlines three ways to create custom security filter chains, and demonstrates how to implement and register a custom filter within the Spring Security filter chain.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Understanding Spring Security’s Core FilterChainProxy and Adding Custom Filters

Core Filter Creation Principle

Spring Security relies on a chain of Filter objects to handle CSRF, authentication, authorization, session management, and other concerns. These filters are encapsulated in DefaultSecurityFilterChain , which is ultimately added to a FilterChainProxy bean named springSecurityFilterChain .

Creation of FilterChainProxy and the default filter chain follows these steps:

public class WebSecurityConfiguration {
    @Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
    public Filter springSecurityFilterChain() throws Exception {
        // Detect custom SecurityConfigurer (WebSecurityConfigurerAdapter) or custom SecurityFilterChain beans
        boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty();
        boolean hasFilterChain = !this.securityFilterChains.isEmpty();
        Assert.state(!(hasConfigurers && hasFilterChain), "Found WebSecurityConfigurerAdapter as well as SecurityFilterChain. Please select just one.");
        if (!hasConfigurers && !hasFilterChain) {
            WebSecurityConfigurerAdapter adapter = this.objectObjectPostProcessor.postProcess(new WebSecurityConfigurerAdapter() {});
            this.webSecurity.apply(adapter);
        }
        // Apply any custom WebSecurityCustomizer beans
        for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {
            customizer.customize(this.webSecurity);
        }
        // Build the FilterChainProxy
        return this.webSecurity.build();
    }
}

The WebSecurity#build method assembles the final FilterChainProxy :

public final class WebSecurity {
    private final List<RequestMatcher> ignoredRequests = new ArrayList<>();
    protected Filter performBuild() throws Exception {
        int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
        List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
        for (RequestMatcher ignoredRequest : this.ignoredRequests) {
            securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
        }
        for (SecurityBuilder<? extends SecurityFilterChain> builder : this.securityFilterChainBuilders) {
            securityFilterChains.add(builder.build());
        }
        FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
        filterChainProxy.afterPropertiesSet();
        return filterChainProxy;
    }
}

Ways to Create a DefaultSecurityFilterChain

There are three main approaches:

Custom SecurityFilterChain bean – when this bean exists, a WebSecurityConfigurerAdapter cannot be used.

@Component
public class CustomSecurityFilterChain implements SecurityFilterChain {
    @Override
    public boolean matches(HttpServletRequest request) { return false; }
    @Override
    public List<Filter> getFilters() { return new ArrayList<>(); }
}

Custom WebSecurityCustomizer bean – used to define URIs that should be ignored by security.

@Component
public class CustomWebSecurity implements WebSecurityCustomizer {
    @Override
    public void customize(WebSecurity web) {
        web.ignoring().antMatchers("/demos/home");
    }
}

Custom WebSecurityConfigurerAdapter subclass – the most common way; it contributes an HttpSecurity instance to the security filter chain builders.

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    // ... override configure(HttpSecurity http) ...
}

Custom Filter Implementation

To add your own processing logic, create a filter that extends OncePerRequestFilter and register it in the security configuration.

@Component
public class AutoAuthenticationFilter extends OncePerRequestFilter {
    @Resource
    private AuthenticationManager authenticationManager;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken("admin", "123123");
        authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
        Authentication auth = authenticationManager.authenticate(authToken);
        if (auth != null) {
            SecurityContextHolder.getContext().setAuthentication(auth);
            request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());
        }
        System.out.println("--------------------------Auto Authentication Filter...");
        filterChain.doFilter(request, response);
    }
}

Register the filter before UsernamePasswordAuthenticationFilter in WebSecurityConfigurerAdapter#configure(HttpSecurity http):

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Resource
    private AutoAuthenticationFilter authFilter;
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(authFilter, UsernamePasswordAuthenticationFilter.class);
    }
}

Summary

Understanding the implementation details of core filter creation (FilterChainProxy and DefaultSecurityFilterChain).

Applying custom filters to extend Spring Security’s authentication flow.

Next article will cover database‑based user authentication.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaBackend DevelopmentCustom Filterspring-securityFilterChainProxy
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.