Spring Security 6.3 新特性

Spring Security 6.3 提供了许多新特性。以下是此版本的亮点,或者您可以查看 发行说明 以了解每个特性和错误修复的详细列表。

被动 JDK 序列化支持

在对 JDK 序列化安全组件的支持方面,Spring Security 历来都比较积极,每个序列化版本只支持一个 Spring Security 次要版本。这意味着如果您有 JDK 序列化的安全组件,则需要在升级到下一个 Spring Security 版本之前将其移除,因为它们将不再可反序列化。

现在 Spring Security 每六个月发布一个次要版本,这变成了一个更大的痛点。为了解决这个问题,Spring Security 现在将 保持对 JDK 序列化的被动性,就像它对 JSON 序列化所做的那样,从而实现更无缝的升级。

授权

在过去的几个版本中,一个持续的主题是重构和改进 Spring Security 的授权子系统。从用 `AuthorizationManager` 替换 `AccessDecisionManager` API 开始,现在我们能够添加一些令人兴奋的新特性。

注解参数 - #14480

第一个 6.3 特性是 对注解参数的支持。考虑 Spring Security 对 元注解 的支持,例如:

  • Java

  • Kotlin

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@PreAuthorize("hasAuthority('SCOPE_message:read')")
public @interface HasMessageRead {}
Kotlin
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@PreAuthorize("hasAuthority('SCOPE_message:read')")
annotation class HasMessageRead

在此版本之前,只有当它在代码库中广泛使用时,这样的功能才会有用。但是现在,您可以添加参数,如下所示:

  • Java

  • Kotlin

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@PreAuthorize("hasAuthority('SCOPE_{scope}')")
public @interface HasScope {
	String scope();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@PreAuthorize("hasAuthority('SCOPE_{scope}')")
annotation class HasScope (val scope:String)

从而可以执行以下操作:

  • Java

  • Kotlin

@HasScope("message:read")
public String method() { ... }
@HasScope("message:read")
fun method(): String { ... }

并在更多地方应用您的 SpEL 表达式。

安全返回值 - #14596, #14597

自从 Spring Security 诞生之初,您就可以使用@PreAuthorize@PostAuthorize注解 Spring Bean。但是,控制器、服务和存储库并非您唯一需要保护的内容。例如,对于一个域对象Order,只有管理员才能调用Order#getPayment方法,该如何处理呢?

现在在 6.3 版本中,您也可以注解这些方法。首先,像注解 Spring Bean 一样注解getPayment方法

  • Java

  • Kotlin

public class Order {

	@HasScope("payment:read")
	Payment getPayment() { ... }

}
class Order {

	@HasScope("payment:read")
	fun getPayment(): Payment { ... }

}
  • Java

  • Kotlin

public interface OrderRepository implements CrudRepository<Order, String> {

	@AuthorizeReturnObject
	Optional<Order> findOrderById(String id);

}
interface OrderRepository : CrudRepository<Order, String> {
    @AuthorizeReturnObject
    fun findOrderById(id: String?): Optional<Order?>?
}

此时,Spring Security 将通过代理Order实例来保护从findOrderById返回的任何Order

错误处理 - #14598#14600#14601

  • Java

  • Kotlin

public class Payment {
    @HandleAuthorizationDenied(handlerClass=Mask.class)
    @PreAuthorize("hasAuthority('card:read')")
    public String getCreditCardNumber() { ... }
}
class Payment {
    @HandleAuthorizationDenied(handlerClass=Mask.class)
    @PreAuthorize("hasAuthority('card:read')")
    fun getCreditCardNumber(): String { ... }
}

并发布一个Mask Bean

  • Java

  • Kotlin

@Component
public class Mask implements MethodAuthorizationDeniedHandler {
	@Override
    public Object handleDeniedInvocation(MethodInvocation invocation, AuthorizationResult result) {
		return "***";
    }
}
@Component
class Mask : MethodAuthorizationDeniedHandler {
    fun handleDeniedInvocation(invocation: MethodInvocation?, result: AuthorizationResult?): Any = "***"
}

则对Payment#getCreditCardNumber的任何未授权调用都将返回***而不是实际的数字。

您可以在最新的 Spring Security Data 示例中看到所有这些功能协同工作。

密码泄露检查 - #7395

如果您要允许用户选择密码,则务必确保该密码尚未泄露。Spring Security 6.3 使此操作变得非常简单,只需发布一个CompromisedPasswordChecker Bean即可。

  • Java

  • Kotlin

@Bean
public CompromisedPasswordChecker compromisedPasswordChecker() {
    return new HaveIBeenPwnedRestApiPasswordChecker();
}
@Bean
fun compromisedPasswordChecker(): CompromisedPasswordChecker = HaveIBeenPwnedRestApiPasswordChecker()

spring-security-rsa 现已成为 Spring Security 的一部分 - #14202

自 2017 年以来,Spring Security 一直在进行一项长期计划,即将各种 Spring Security 扩展整合到 Spring Security 本身中。在 6.3 版本中,spring-security-rsa 成为这些项目中的最新一个,这将有助于团队长期维护和添加功能。

spring-security-rsa 提供了许多方便的BytesEncryptor实现,以及更简单的KeyStore操作 API

OAuth 2.0 令牌交换授权 - #5199

Spring Security 中投票最高的 OAuth 2.0 功能之一现在已在 6.3 版本中实现,即对OAuth 2.0 令牌交换授权的支持。

对于任何配置为令牌交换的客户端,您可以通过将TokenExchangeAuthorizedClientProvider实例添加到您的OAuth2AuthorizedClientManager中来激活它,如下所示

  • Java

  • Kotlin

@Bean
public OAuth2AuthorizedClientProvider tokenExchange() {
	return new TokenExchangeOAuth2AuthorizedClientProvider();
}
@Bean
fun tokenExchange(): OAuth2AuthorizedClientProvider = TokenExchangeOAuth2AuthorizedClientProvider()

然后像往常一样使用@RegisteredOAuth2AuthorizedClient注解来检索具有资源服务器所需扩展权限的相应令牌。

其他亮点

  • gh-14655 - 添加DelegatingAuthenticationConverter

  • gh-6192 - 在 WebFlux 上添加并发会话控制(文档

  • gh-14193 - 添加对 CAS 网关身份验证的支持

  • gh-13259 - 自定义何时调用 UserInfo

  • gh-14168 - 在 OAuth2AuthorizationRequestRedirectFilter 中引入可自定义的 AuthorizationFailureHandler

  • gh-14672 - 自定义从 OidcUserRequest 和 OidcUserInfo 映射 OidcUser

  • gh-13763 - 简化响应式 OAuth2 客户端组件模型的配置

  • gh-14758 - 使用示例更新响应式 OAuth2 文档的着陆页(文档

  • gh-10538 - 支持基于证书的 JWT 访问令牌验证

  • gh-14265 - 支持 UserInfo 响应中的嵌套用户名

  • gh-14449 - 添加SecurityContext参数解析器

  • gh-11440 - 简化禁用application/x-www-form-urlencoded编码客户端 ID 和密钥(Servlet 文档响应式文档

有关详尽列表,请参阅6.3.0-RC16.3.0-M36.3.0-M26.3.0-M1的发布说明。