此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Security 6.4.5! |
Kotlin 配置
Spring Security Kotlin 配置从 Spring Security 5.3 开始可用。 它允许用户使用本机 Kotlin DSL 配置 Spring Security。
Spring Security 提供了一个示例应用程序来演示 Spring Security Kotlin 配置的使用。 |
HttpSecurity 安全
Spring Security 如何知道我们要要求所有用户都经过身份验证?
Spring Security 如何知道我们想要支持基于表单的身份验证?
有一个配置类(称为SecurityFilterChain
),该 API 的调用正在后台调用。
它使用以下默认实现进行配置:
import org.springframework.security.config.annotation.web.invoke
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
authorizeHttpRequests {
authorize(anyRequest, authenticated)
}
formLogin { }
httpBasic { }
}
return http.build()
}
确保导入org.springframework.security.config.annotation.web.invoke 函数在您的类中启用 Kotlin DSL,因为 IDE 并不总是自动导入该方法,从而导致编译问题。 |
默认配置(如前面的示例所示):
-
确保对我们的应用程序的任何请求都需要对用户进行身份验证
-
允许用户使用基于表单的登录进行身份验证
-
允许用户使用 HTTP 基本身份验证进行身份验证
请注意,此配置与 XML 命名空间配置类似:
<http>
<intercept-url pattern="/**" access="authenticated"/>
<form-login />
<http-basic />
</http>
多个 HttpSecurity 实例
为了有效地管理某些区域需要不同保护的应用程序的安全性,我们可以在应用程序上使用多个过滤器链以及securityMatcher
DSL 方法。
这种方法允许我们定义针对应用程序的特定部分量身定制的不同安全配置,从而增强整体应用程序安全性和控制力。
我们可以配置多个HttpSecurity
实例,就像我们可以有多个<http>
块。
关键是要注册多个SecurityFilterChain
@Bean
s.
以下示例对以/api/
:
import org.springframework.security.config.annotation.web.invoke
@Configuration
@EnableWebSecurity
class MultiHttpSecurityConfig {
@Bean (1)
open fun userDetailsService(): UserDetailsService {
val users = 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
}
@Bean
@Order(1) (2)
open fun apiFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
securityMatcher("/api/**") (3)
authorizeHttpRequests {
authorize(anyRequest, hasRole("ADMIN"))
}
httpBasic { }
}
return http.build()
}
@Bean (4)
open fun formLoginFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
authorizeHttpRequests {
authorize(anyRequest, authenticated)
}
formLogin { }
}
return http.build()
}
}
1 | 照常配置 Authentication。 |
2 | 创建SecurityFilterChain 包含@Order 以指定SecurityFilterChain 应首先考虑。 |
3 | 这http.securityMatcher() 声明此HttpSecurity 仅适用于以/api/ . |
4 | 创建SecurityFilterChain .
如果 URL 不以/api/ ,则使用此配置。
此配置在apiFilterChain ,因为它有一个@Order 值1 (否@Order 默认为 last)。 |
选择securityMatcher
或requestMatchers
一个常见的问题是:
这两者之间有什么区别
http.securityMatcher()
method 和requestMatchers()
用于请求授权(即在http.authorizeHttpRequests()
)?
要回答这个问题,了解每个HttpSecurity
实例用于构建SecurityFilterChain
包含一个RequestMatcher
匹配传入请求。
如果请求与SecurityFilterChain
具有更高的优先级(例如@Order(1)
),则可以针对优先级较低的过滤器链(例如 no@Order
).
多个过滤器链的匹配逻辑由 |
默认的RequestMatcher
匹配任何请求,以确保 Spring Security 默认保护所有请求。
指定 |
如果没有过滤器链与特定请求匹配,则该请求不受 Spring Security 保护。 |
以下示例演示了一个筛选条件链,该链仅保护以/secured/
:
import org.springframework.security.config.annotation.web.invoke
@Configuration
@EnableWebSecurity
class PartialSecurityConfig {
@Bean
open fun userDetailsService(): UserDetailsService {
// ...
}
@Bean
open fun securedFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
securityMatcher("/secured/**") (1)
authorizeHttpRequests {
authorize("/secured/user", hasRole("USER")) (2)
authorize("/secured/admin", hasRole("ADMIN")) (3)
authorize(anyRequest, authenticated) (4)
}
httpBasic { }
formLogin { }
}
return http.build()
}
}
1 | 以/secured/ 将受到保护,但任何其他请求都不受保护。 |
2 | 请求/secured/user 需要ROLE_USER 柄。 |
3 | 请求/secured/admin 需要ROLE_ADMIN 柄。 |
4 | 任何其他请求(例如/secured/other ) 只需要经过身份验证的用户。 |
建议提供 |
请注意,requestMatchers
method 仅适用于单个授权规则。
此处列出的每个请求也必须与总体securityMatcher
对于这个特定的HttpSecurity
实例用于创建SecurityFilterChain
.
用anyRequest()
在此示例中匹配此特定SecurityFilterChain
(必须以/secured/
).
有关更多信息,请参见授权 HttpServletRequests |
SecurityFilterChain
端点
S 中的SecurityFilterChain
直接提供终端节点,例如UsernamePasswordAuthenticationFilter
它由http.formLogin()
并提供POST /login
端点。
在上面的示例中,/login
endpoint 不匹配http.securityMatcher("/secured/**")
因此,该应用程序不会有任何GET /login
或POST /login
端点。
此类请求将返回404 Not Found
.
这通常让用户感到惊讶。
指定http.securityMatcher()
影响SecurityFilterChain
.
但是,它不会自动影响筛选条件链提供的终端节点。
在这种情况下,您可能需要自定义您希望筛选条件链提供的任何终端节点的 URL。
以下示例演示了一个配置,该配置保护以/secured/
并拒绝所有其他请求,同时还自定义SecurityFilterChain
:
import org.springframework.security.config.annotation.web.invoke
@Configuration
@EnableWebSecurity
class SecuredSecurityConfig {
@Bean
open fun userDetailsService(): UserDetailsService {
// ...
}
@Bean
@Order(1)
open fun securedFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
securityMatcher("/secured/**") (1)
authorizeHttpRequests {
authorize(anyRequest, authenticated) (2)
}
formLogin { (3)
loginPage = "/secured/login"
loginProcessingUrl = "/secured/login"
permitAll = true
}
logout { (4)
logoutUrl = "/secured/logout"
logoutSuccessUrl = "/secured/login?logout"
permitAll = true
}
}
return http.build()
}
@Bean
open fun defaultFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
authorizeHttpRequests {
authorize(anyRequest, denyAll) (5)
}
}
return http.build()
}
}
1 | 以/secured/ 将受到此过滤器链的保护。 |
2 | 以/secured/ 需要经过身份验证的用户。 |
3 | 自定义表单登录以在 URL 前添加前缀/secured/ . |
4 | 自定义注销以在 URL 前添加/secured/ . |
5 | 所有其他请求都将被拒绝。 |
此示例自定义登录和注销页面,这将禁用 Spring Security 生成的页面。
您必须为 |
真实示例
以下示例演示了将所有这些元素放在一起的更真实的配置:
import org.springframework.security.config.annotation.web.invoke
@Configuration
@EnableWebSecurity
class BankingSecurityConfig {
@Bean (1)
open fun userDetailsService(): UserDetailsService {
val users = User.withDefaultPasswordEncoder()
val manager = InMemoryUserDetailsManager()
manager.createUser(users.username("user1").password("password").roles("USER", "VIEW_BALANCE").build())
manager.createUser(users.username("user2").password("password").roles("USER").build())
manager.createUser(users.username("admin").password("password").roles("ADMIN").build())
return manager
}
@Bean
@Order(1) (2)
open fun approvalsSecurityFilterChain(http: HttpSecurity): SecurityFilterChain {
val approvalsPaths = arrayOf("/accounts/approvals/**", "/loans/approvals/**", "/credit-cards/approvals/**")
http {
securityMatcher(*approvalsPaths)
authorizeHttpRequests {
authorize(anyRequest, hasRole("ADMIN"))
}
httpBasic { }
}
return http.build()
}
@Bean
@Order(2) (3)
open fun bankingSecurityFilterChain(http: HttpSecurity): SecurityFilterChain {
val bankingPaths = arrayOf("/accounts/**", "/loans/**", "/credit-cards/**", "/balances/**")
val viewBalancePaths = arrayOf("/balances/**")
http {
securityMatcher(*bankingPaths)
authorizeHttpRequests {
authorize(viewBalancePaths, hasRole("VIEW_BALANCE"))
authorize(anyRequest, hasRole("USER"))
}
}
return http.build()
}
@Bean (4)
open fun defaultSecurityFilterChain(http: HttpSecurity): SecurityFilterChain {
val allowedPaths = arrayOf("/", "/user-login", "/user-logout", "/notices", "/contact", "/register")
http {
authorizeHttpRequests {
authorize(allowedPaths, permitAll)
authorize(anyRequest, authenticated)
}
formLogin {
loginPage = "/user-login"
loginProcessingUrl = "/user-login"
}
logout {
logoutUrl = "/user-logout"
logoutSuccessUrl = "/?logout"
}
}
return http.build()
}
}
1 | 首先配置身份验证设置。 |
2 | 定义一个SecurityFilterChain 实例替换为@Order(1) ,这意味着此筛选条件链将具有最高优先级。
此筛选条件链仅适用于以/accounts/approvals/ ,/loans/approvals/ 或/credit-cards/approvals/ .
对此筛选条件链的请求需要ROLE_ADMIN 颁发机构并允许 HTTP 基本身份验证。 |
3 | 接下来,创建另一个SecurityFilterChain 实例替换为@Order(2) 这将被视为第二名。
此筛选条件链仅适用于以/accounts/ ,/loans/ ,/credit-cards/ 或/balances/ .
请注意,由于此筛选条件链是第二个,因此包含/approvals/ 将匹配上一个过滤器链,并且不会与此过滤器链匹配。
对此筛选条件链的请求需要ROLE_USER 柄。
此过滤器链未定义任何身份验证,因为下一个(默认)过滤器链包含该配置。 |
4 | 最后,创建一个额外的SecurityFilterChain 实例中没有@Order 注解。
此配置将处理其他过滤器链未涵盖的请求,并将最后处理(否@Order 默认为 last)。
匹配的请求数 ,/ /user-login ,/user-logout ,/notices ,/contact 和/register 允许无需身份验证的访问。
任何其他请求都要求用户进行身份验证才能访问其他筛选条件链未明确允许或保护的任何 URL。 |