1. 概述

Spring Security 5.3 引入了 Kotlin DSL(领域特定语言),用于简化安全配置。DSL 允许我们使用 Kotlin 的语法特性,写出更简洁、可读性更强的安全配置代码。

本文将介绍 Kotlin DSL 的使用方式,包括如何配置安全策略、用户管理以及接口权限控制,并通过 cURL 命令进行验证。


2. Spring Security Kotlin DSL 使用详解

2.1 安全配置

在传统的 Spring Security 配置中,我们通常通过 Java 配置类创建一个 SecurityFilterChain bean 来定义安全策略:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .authorizeRequests(authz -> authz
            .antMatchers("/greetings/**").hasAuthority("ROLE_ADMIN")
            .antMatchers("/**").permitAll()
        )
        .httpBasic(basic -> {});
    return http.build();
}

这段代码限制了 /greetings/** 路径只能由拥有 ROLE_ADMIN 权限的用户访问,其余路径对所有人开放。

使用 Kotlin DSL 后,同样的配置可以更简洁地写成:

@Bean
fun filterChain(http: HttpSecurity): SecurityFilterChain {
    http {
        authorizeRequests {
            authorize("/greetings/**", hasAuthority("ROLE_ADMIN"))
            authorize("/**", permitAll)
        }
        httpBasic {}
    }
    return http.build()
}

优势:语法更简洁,结构清晰,符合 Kotlin 的函数式风格。

多组安全配置

如果希望为不同接口路径配置不同的安全策略,可以通过定义多个 SecurityFilterChain bean 实现:

@Order(1)
@Configuration
class AdminSecurityConfiguration {
    @Bean
    fun filterChainAdmin(http: HttpSecurity): SecurityFilterChain {
        http {
            securityMatcher("/greetings/**")
            authorizeRequests {
                authorize("/greetings/**", hasAuthority("ROLE_ADMIN"))
            }
            httpBasic {}
        }
        return http.build()
    }
}

@Configuration
class BasicSecurityConfiguration {
    @Bean
    fun filterChainBasic(http: HttpSecurity): SecurityFilterChain {
        http {
            authorizeRequests {
                authorize("/**", permitAll)
            }
            httpBasic {}
        }
        return http.build()
    }
}

⚠️ 注意@Order(1) 用于指定配置顺序,确保 /greetings/** 的安全策略优先于全局配置。


2.2 用户配置

为了验证安全配置是否生效,我们需要创建两个用户:一个普通用户 user(角色为 USER),一个管理员用户 admin(角色为 USER 和 ADMIN)。

Java 配置方式如下:

@Bean
public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
    UserDetails user = User.withDefaultPasswordEncoder()
        .username("user").password("password").roles("USER").build();
    UserDetails admin = User.withDefaultPasswordEncoder()
        .username("admin").password("password").roles("USER", "ADMIN").build();

    InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
    inMemoryUserDetailsManager.createUser(user);
    inMemoryUserDetailsManager.createUser(admin);
    return inMemoryUserDetailsManager;
}

使用 Kotlin DSL 配置:

beans {
    bean {
        fun user(user: String, password: String, vararg roles: String) =
            User.withDefaultPasswordEncoder().username(user).password(password)
                .roles(*roles).build()
        InMemoryUserDetailsManager(user("user", "password", "USER"), 
            user("admin", "password", "USER", "ADMIN"))
    }
}

优势:DSL 更加紧凑,函数式风格更易维护。


2.3 接口配置

接下来我们定义一个 REST 接口 /greetings,用于测试安全配置是否生效:

bean {
    router {
        GET("/greetings") {
            request -> request.principal().map { it.name }
                .map { ServerResponse.ok().body(mapOf("greeting" to "Hello $it")) }
                .orElseGet { ServerResponse.badRequest().build() }
        }
    }
}

这段代码定义了一个 GET 接口,返回当前登录用户的问候语。


3. 测试安全接口

使用 cURL 测试访问权限

首先尝试用普通用户 user 访问 /greetings

$ curl -v -u user:password http://localhost:8080/greetings

预期返回 403 Forbidden,说明权限校验生效。

接着用管理员用户 admin 访问:

$ curl -v -u admin:password http://localhost:8080/greetings

预期返回 200 OK 并包含如下响应体:

{
  "greeting": "Hello admin"
}

结论:Kotlin DSL 配置正确,权限控制正常工作。


4. 小结

通过本文我们学习了如何使用 Spring Security 提供的 Kotlin DSL 来配置安全策略。DSL 语法简洁、结构清晰,非常适合 Kotlin 项目使用。同时我们也通过 cURL 命令验证了配置的正确性。

如需查看完整代码,请访问:GitHub 项目地址


原始标题:Spring Security with Kotlin DSL