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 成为这些项目的最新项目,这将帮助团队长期维护和添加功能。

OAuth 2.0 令牌交换授权 - #5199

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

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

  • 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 的发行说明。