0%
August 7, 2024

CORS Configuration for HandlerInterceptors via Spring Security

kotlin

springboot

Failed Config

For example, documentation provides an example that is similar to the following:

@Configuration
class GlobalCorsConfig {
    @Bean
    fun corsConfigurer(): WebMvcConfigurer {
        return object : WebMvcConfigurer {
            override fun addCorsMappings(registry: CorsRegistry) {
                registry.addMapping("/**") 
                    .allowedOrigins("*") 
                    .allowCredentials(true) 
                    .allowedMethods("GET", "POST", "PUT", "DELETE") 
                    .allowedHeaders("*") 
                    .exposedHeaders("Header1", "Header2")
            }
        }
    }
}

but this fails to get custom header in HandlerInterceptors.

Successful SecurityConfig for HandlerInterceptors

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpStatus
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.http.SessionCreationPolicy
import org.springframework.security.web.SecurityFilterChain
import org.springframework.security.web.authentication.HttpStatusEntryPoint
import org.springframework.web.cors.CorsConfiguration
import org.springframework.web.cors.CorsConfigurationSource
import org.springframework.web.cors.UrlBasedCorsConfigurationSource

@Configuration
@EnableWebSecurity
class SecurityConfig {

    fun corsConfigurationSource(): CorsConfigurationSource {
        val config = CorsConfiguration()
        config.allowedOrigins = listOf("http://localhost:5173", "http://localhost:5173/")
        config.allowedMethods = listOf("GET", "POST", "PUT", "DELETE", "OPTIONS")
        config.allowedHeaders = listOf("*")
        val source = UrlBasedCorsConfigurationSource()
        source.registerCorsConfiguration("/**", config)
        return source
    }

    @Bean
    fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
        http.exceptionHandling { c ->
            c.authenticationEntryPoint(
                HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)
            )
        }
            .csrf { c -> c.disable() }
            .cors { c -> c.configurationSource(corsConfigurationSource()) }
            .sessionManagement { c -> c.sessionCreationPolicy(SessionCreationPolicy.STATELESS) }
            .authorizeHttpRequests { req -> req.anyRequest().permitAll() }
        return http.build()
    }
}