springboot security different SecurityFilterChain for api and controllers

129 views Asked by At

I have my springboot app built with maven that has the normal navigation protected with login and now I would like to have the /api path protected with api key. I tried to implement the tso mechanisms and they work but separetely. Indeed, having this as security filter chain:

@Bean
public SecurityFilterChain httpFilterChain(final HttpSecurity http) throws Exception {
    return http.cors(withDefaults())
            .csrf(csrf -> csrf.ignoringRequestMatchers("/api/**"))
            .authorizeHttpRequests(authorize -> authorize.anyRequest().permitAll())
            .formLogin(form -> form
                    .loginPage("/login")
                    .failureUrl("/login?loginError=true"))
            .logout(logout -> logout
                    .logoutSuccessUrl("/login?logoutSuccess=true")
                    .deleteCookies("JSESSIONID"))
            .exceptionHandling(exception -> exception
                    .authenticationEntryPoint(new
                            LoginUrlAuthenticationEntryPoint("/login?loginRequired=true")))
            .build();
}

protects with login and password also the /api/ path, and having this:

 @Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.csrf(AbstractHttpConfigurer::disable)
            .authorizeHttpRequests(authorizationManagerRequestMatcherRegistry ->
                    authorizationManagerRequestMatcherRegistry.requestMatchers("/api/**").
                            authenticated())
            .httpBasic(Customizer.withDefaults())
            .sessionManagement(httpSecuritySessionManagementConfigurer ->
                    httpSecuritySessionManagementConfigurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .addFilterBefore(new AuthenticationFilter(),UsernamePasswordAuthenticationFilter.class);
    return http.build();
}

asks about api key also navigating every path.

What I would like to obtain is to protect the /api with the last bean and at the same time protect the other navigation except /api/ with the login with password on the first bean. How can i do that?

2

There are 2 answers

3
yao Mr On

You can set up two securityfilterchain the one is a special and another is a default, and then set up the order like this

    @Bean
    @Order(1)
    fun demoFilterChain(http: HttpSecurity): SecurityFilterChain {

        http
            .securityMatcher("/demo/**")
            .authorizeHttpRequests {
                it.anyRequest().permitAll()
            }
        return http.build()
    }

    @Bean
    @Order(2)
    fun defaultFilterChain(http: HttpSecurity): SecurityFilterChain {
        http
            .csrf {
                it.disable()
            }
            .authorizeHttpRequests {
                it
                    .anyRequest().authenticated()
            }.formLogin { }

        return http.build()
    }

Put the special securityfilterchain in front and the default one after. That way, if it doesn't match, the default policy will be gone.

6
coverDJ234 On

If this is what you mean:

@Bean
@Order(1)
public SecurityFilterChain apiFilterChain(final HttpSecurity http) throws Exception {
    
http.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(authorizationManagerRequestMatcherRegistry ->
authorizationManagerRequestMatcherRegistry.requestMatchers("/api/**").
authenticated())
.httpBasic(Customizer.withDefaults())
.sessionManagement(httpSecuritySessionManagementConfigurer ->
httpSecuritySessionManagementConfigurer.sessionCreationPolicy(
SessionCreationPolicy.STATELESS))
.addFilterBefore(new AuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class);
return http.build();
}

@Bean
@Order(2)
public SecurityFilterChain httpFilterChain(final HttpSecurity http) throws Exception {
    
      http.cors(withDefaults())
      .csrf(csrf -> csrf.ignoringRequestMatchers("/api/**"))
      .authorizeHttpRequests(authorize -> authorize.anyRequest().permitAll())
      .formLogin(form -> form
      .loginPage("/login")
      .failureUrl("/login?loginError=true"))
     .logout(logout -> logout
      .logoutSuccessUrl("/login?logoutSuccess=true")
      .deleteCookies("JSESSIONID"))
      .exceptionHandling(exception -> exception
      .authenticationEntryPoint(new
      LoginUrlAuthenticationEntryPoint("/login?loginRequired=true")));
    

     return http.build();
}

the API token is requested also navigating every path for instance localhost:8080/clients and not only /api/