sequence

This article describes a very common problem with spring Security’s custom filter, which is that the filter is executed twice.

repetition

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    public DemoFilter demoFilter() {return new DemoFilter();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .addFilterBefore(demoFilter(),AnonymousAuthenticationFilter.class)
                .authorizeRequests()
                .antMatchers("/login"."/css/**"."/js/**"."/fonts/**").permitAll() .anyRequest().authenticated(); }}Copy the code

DemoFilter is as follows

public class DemoFilter extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //dosomething filterChain.doFilter(servletRequest, servletResponse); }}Copy the code

why

Beans of GenericFilterBean hosted in the Spring container are automatically added to the filter chain of the servlet, and as defined above, Also the additional filter before joining AnonymousAuthenticationFilter to spring security. Spring Security, on the other hand, is also a series of filters that are executed before MVC filters. Therefore, in the case of passing authentication, it will be executed one after another.

The solution

Plan 1

Instead of hosting filter to Spring, just new, for example

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .addFilterBefore(new DemoFilter(),AnonymousAuthenticationFilter.class)
                .authorizeRequests()
                .antMatchers("/login"."/css/**"."/js/**"."/fonts/**").permitAll() .anyRequest().authenticated(); }}Copy the code

Scheme 2

Sometimes filter need to access the resources of the spring container, managed to container may be better, so this time, you can make a tag like FilterSecurityInterceptor FILTER_APPLIED

public class DemoFilter extends GenericFilterBean {

    private static final String FILTER_APPLIED = "__spring_security_demoFilter_filterApplied";

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        if(servletRequest.getAttribute(FILTER_APPLIED) ! = null) { filterChain.doFilter(servletRequest, servletResponse);return; } / /do something
        servletRequest.setAttribute(FILTER_APPLIED,true); filterChain.doFilter(servletRequest, servletResponse); }}Copy the code

doc

  • Spring security custom filter called multiple times