spring-projects / spring-security

Spring Security
http://spring.io/projects/spring-security
Apache License 2.0
8.55k stars 5.79k forks source link

Support `GrantedAuthorityDefaults` Bean in authorizeHttpRequests Kotlin DSL #15171

Closed ttasjwi closed 2 weeks ago

ttasjwi commented 1 month ago

Overview

Expected Behavior

Current Behavior

Example Code

1. Common - Controller

@RestController
class SecurityController {

    @GetMapping("/")
    fun index(): String {
        return "index"
    }

    @GetMapping("/user")
    fun user(): String {
        return "user"
    }

    @GetMapping("/db")
    fun db(): String {
        return "db"
    }

    @GetMapping("/admin")
    fun admin(): String {
        return "admin"
    }
}

2. Common - SecurityConfig

    @Bean
    fun grantedAuthorityDefaults(): GrantedAuthorityDefaults {
        return GrantedAuthorityDefaults("MYPREFIX_")
    }

    @Bean
    fun userDetailsService(): UserDetailsService {
        val user = User.withUsername("user").password("{noop}1111").authorities("MYPREFIX_USER").build()
        val db = User.withUsername("db").password("{noop}1111").authorities("MYPREFIX_DB").build()
        val admin = User.withUsername("admin").password("{noop}1111").authorities("MYPREFIX_ADMIN").build()
        return InMemoryUserDetailsManager(user, db, admin)
    }

3. JavaDSL SecurityFilterChain

    @Bean
    fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
        http
            .authorizeHttpRequests {
                it
                    .requestMatchers("/user").hasRole("USER")
                    .requestMatchers("/admin").hasRole("ADMIN")
                    .requestMatchers("/db").hasRole("DB")
                    .anyRequest().authenticated()
            }
            .formLogin(Customizer.withDefaults())
        return http.build()
    }

4. KotlinDSL SecurityFilterChain

    @Bean
    fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            authorizeHttpRequests {
                authorize("/user", hasRole("USER"))
                authorize("/admin", hasRole("ADMIN"))
                authorize("/db", hasRole("DB"))
                authorize(anyRequest, authenticated)
            }
            formLogin { }
        }
        return http.build()
    }

Probable Cause

jzheaux commented 2 weeks ago

Thanks for the report, @ttasjwi. This is now merged into main and will go out in the next milestone. Please check the latest 6.4 snapshot to confirm the feature works for you.