For the latest stable version, please use Spring Security 6.4.1!

Kotlin Configuration

Spring Security provides a sample application which demonstrates the use of Spring Security Kotlin Configuration.

HttpSecurity

How does Spring Security know that we want to require all users to be authenticated? How does Spring Security know we want to support form based authentication? Actually, there is a bean that is being invoked behind the scenes called SecurityFilterChain. It is configured with the following default implementation:

import org.springframework.security.config.annotation.web.invoke

@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
   http {
        authorizeRequests {
            authorize(anyRequest, authenticated)
        }
       formLogin { }
       httpBasic { }
    }
    return http.build()
}
Make sure that import the invoke function in your class, sometimes the IDE will not auto-import it causing compilation issues.

The default configuration above:

  • Ensures that any request to our application requires the user to be authenticated

  • Allows users to authenticate with form based login

  • Allows users to authenticate with HTTP Basic authentication

You will notice that this configuration is quite similar the XML Namespace configuration:

<http>
	<intercept-url pattern="/**" access="authenticated"/>
	<form-login />
	<http-basic />
</http>

Multiple HttpSecurity

We can configure multiple HttpSecurity instances just as we can have multiple <http> blocks. The key is to register multiple SecurityFilterChain @Beans. For example, the following is an example of having a different configuration for URL’s that start with /api/.

import org.springframework.security.config.annotation.web.invoke

@EnableWebSecurity
class MultiHttpSecurityConfig {
    @Bean                                                            (1)
    public fun userDetailsService(): UserDetailsService {
        val users: User.UserBuilder = User.withDefaultPasswordEncoder()
        val manager = InMemoryUserDetailsManager()
        manager.createUser(users.username("user").password("password").roles("USER").build())
        manager.createUser(users.username("admin").password("password").roles("USER","ADMIN").build())
        return manager
    }

    @Order(1)                                                        (2)
    @Bean
    open fun apiFilterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            securityMatcher("/api/**")                               (3)
            authorizeRequests {
                authorize(anyRequest, hasRole("ADMIN"))
            }
            httpBasic { }
        }
        return http.build()
    }

    @Bean                                                            (4)
    open fun formLoginFilterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            authorizeRequests {
                authorize(anyRequest, authenticated)
            }
            formLogin { }
        }
        return http.build()
    }
}
1 Configure Authentication as normal
2 Expose an instance of SecurityFilterChain that contains @Order to specify which SecurityFilterChain should be considered first.
3 The http.antMatcher states that this HttpSecurity will only be applicable to URLs that start with /api/
4 Expose another instance of SecurityFilterChain. If the URL does not start with /api/ this configuration will be used. This configuration is considered after apiFilterChain since it has an @Order value after 1 (no @Order defaults to last).