Search code examples
springspring-bootspring-security

Spring security filter order UsernamePasswordAuthenticationFilter


I am a beginner in Spring Security, and I would like to understand the order of the filters. Based on a Github repository that shows how to perform JWT authentication, I noticed in the SecurityConfiguration that the author used .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class) to add his JWT filter before the UsernamePasswordAuthenticationFilter. What I don't understand is that when starting the project in debug mode, the UsernamePasswordAuthenticationFilter is never loaded. Why place his filter before the UsernamePasswordAuthenticationFilter? What happens if the UsernamePasswordAuthenticationFilter is not added? I thought the filter was going to be added at the end of the chain but it is finally placed after the LogoutFilter.

@Configuration
@EnableWebSecurity(debug = true)
@RequiredArgsConstructor
@EnableMethodSecurity
public class SecurityConfiguration {

  private final JwtAuthenticationFilter jwtAuthFilter;
  private final AuthenticationProvider authenticationProvider;
  private final LogoutHandler logoutHandler;

  @Bean
  public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .csrf()
        .disable()
        .authorizeHttpRequests()
        .requestMatchers(
                "/api/v1/auth/**",
                "/v2/api-docs",
                "/v3/api-docs",
                "/v3/api-docs/**",
                "/swagger-resources",
                "/swagger-resources/**",
                "/configuration/ui",
                "/configuration/security",
                "/swagger-ui/**",
                "/webjars/**",
                "/swagger-ui.html"
        )
          .permitAll()


        .requestMatchers("/api/v1/management/**").hasAnyRole(ADMIN.name(), MANAGER.name())


        .requestMatchers(GET, "/api/v1/management/**").hasAnyAuthority(ADMIN_READ.name(), MANAGER_READ.name())
        .requestMatchers(POST, "/api/v1/management/**").hasAnyAuthority(ADMIN_CREATE.name(), MANAGER_CREATE.name())
        .requestMatchers(PUT, "/api/v1/management/**").hasAnyAuthority(ADMIN_UPDATE.name(), MANAGER_UPDATE.name())
        .requestMatchers(DELETE, "/api/v1/management/**").hasAnyAuthority(ADMIN_DELETE.name(), MANAGER_DELETE.name())


       /* .requestMatchers("/api/v1/admin/**").hasRole(ADMIN.name())

        .requestMatchers(GET, "/api/v1/admin/**").hasAuthority(ADMIN_READ.name())
        .requestMatchers(POST, "/api/v1/admin/**").hasAuthority(ADMIN_CREATE.name())
        .requestMatchers(PUT, "/api/v1/admin/**").hasAuthority(ADMIN_UPDATE.name())
        .requestMatchers(DELETE, "/api/v1/admin/**").hasAuthority(ADMIN_DELETE.name())*/


        .anyRequest()
          .authenticated()
        .and()
          .sessionManagement()
          .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
        .authenticationProvider(authenticationProvider)
        .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
        .logout()
        .logoutUrl("/api/v1/auth/logout")
        .addLogoutHandler(logoutHandler)
        .logoutSuccessHandler((request, response, authentication) -> SecurityContextHolder.clearContext())
    ;

    return http.build();
  }
}

If I don't activate my filter chain, I do have the UsernamePasswordAuthenticationFilter. I would like to understand how Spring manages the .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class) in a custom configuration.


Solution

  • Why place his filter before the UsernamePasswordAuthenticationFilter?

    because once you have a jwt token, you don't wanna waste time going through other authentication filters like usernameAndPasswordAuthFilter, you wanna hit your jwtFilter first to save time.

    What happens if the UsernamePasswordAuthenticationFilter is not added?

    It does not matter if UsernamePasswordFilter is in securityFilterChain or not, because each known filter of these has an Order like (100,200,300,...)once you add a filter before it your filter gets assigned an order of (100-1, 200-1, 300-1,...) so even if UsernamePasswordFilter is added or not its order is known in the security filter chain and can be used to assign order to your jwtFilter

    I thought the filter was going to be added at the end of the chain but it is finally placed after the LogoutFilter

    that is reasonable, if you check the order of security filters here you would find that your jwtFilter is inserted before UsernamePasswordFilter.