跳到主要内容

Spring Security 6.4 的新特性

DeepSeek V3 中英对照 What’s New What’s New in Spring Security 6.4

Spring Security 6.4 提供了许多新功能。以下是该版本的主要亮点,或者您可以查看发布说明以获取每个功能和错误修复的详细列表。

弃用通知

随着我们即将迎来 Spring Security 7,及时了解弃用内容变得尤为重要。因此,本节指出了 6.4 版本中的弃用内容。

  • 方法安全 - AuthorizationManager#check 已被弃用,建议使用 AuthorizationManager#authorize。这主要是为了让返回类型可以是一个接口而不是具体的类。如果你正在调用 AuthorizationManager#check,请改为调用 AuthorizationManager#authorize

    与此相关的是,接受 AuthorizationDecisionAuthorizationEventPublisher#publishEvent 已被弃用,建议使用接受 AuthorizationResult 接口的同名方法。

  • 方法安全 - PrePostTemplateDefaults 已被弃用,建议使用更通用的 AnnotationTemplateExpressionDefaults,因为现在 @AuthenticationPrincipal@CurrentSecurityContext 也支持元注解属性。如果你正在构建 PrePostTemplateDefaults,请将其替换为 AnnotationTemplateExpressionDefaults

  • OAuth 2.0 - NimbusOpaqueTokenIntrospector 已被弃用,建议使用 SpringOpaqueTokenIntrospector,以便移除 Spring Security OAuth 2.0 资源服务器对 oidc-oauth2-sdk 包的依赖。如果你正在构建 NimbusOpaqueTokenIntrospector,请将其替换为 SpringOpaqueTokenIntrospector 的构造函数。

  • OAuth 2.0 - DefaultAuthorizationCodeTokenResponseClientDefaultClientCredentialsTokenResponseClientDefaultJwtBearerTokenResponseClientDefaultPasswordTokenResponseClientDefaultRefreshTokenTokenResponseClientDefaultTokenExchangeTokenResponseClient 已被弃用,建议使用它们的 RestClient 等效实现。

    与此相关的是,JwtBearerGrantRequestEntityConverterOAuth2AuthorizationCodeGrantRequestEntityConverterOAuth2ClientCredentialsGrantRequestEntityConverterOAuth2PasswordGrantRequestEntityConverterOAuth2RefreshTokenGrantRequestEntityConverter 已被弃用,建议使用 DefaultOAuth2TokenRequestParametersConverter 实例来替代上述的令牌响应客户端。

    例如,如果你有以下配置:

    private static class MyCustomConverter
    extends AbstractOAuth2AuthorizationGrantRequestEntityConverter<OAuth2AuthorizationCodeGrantRequest> {
    @Override
    protected MultiValueMap<String, String> createParameters
    (OAuth2AuthorizationCodeGrantRequest request) {
    MultiValueMap<String, String> parameters = super.createParameters(request);
    parameters.add("custom", "value");
    return parameters;
    }
    }

    @Bean
    OAuth2AccessTokenResponseClient authorizationCode() {
    DefaultAuthorizationCodeTokenResponseClient client =
    new DefaultAuthorizationCodeTokenResponseClient();
    Converter<AuthorizationCodeGrantRequest, RequestEntity<?>> entityConverter =
    new OAuth2AuthorizationCodeGrantRequestEntityConverter();
    entityConverter.setParametersConverter(new MyCustomConverter());
    client.setRequestEntityConverter(entityConverter);
    return client;
    }
    java

    这个配置已被弃用,因为它使用了 DefaultAuthorizationCodeTokenResponseClientOAuth2AuthorizationCodeGrantRequestEntityConverter。推荐的配置现在是:

    private static class MyCustomConverter implements Converter<OAuth2AuthorizationCodeGrantRequest, Map<String, String>> {
    @Override
    public MultiValueMap<String, String> convert(OAuth2AuthorizeCodeGrantRequest request) {
    MultiValueMap<String, String> parameters = OAuth2AuthorizationCodeGrantRequest.defaultParameters(request);
    parameters.add("custom", "value");
    return parameters;
    }
    }

    @Bean
    OAuth2AccessTokenResponseClient authorizationCode() {
    RestClientAuthorizationCodeTokenResponseClient client =
    new RestClientAuthorizationCodeTokenResponseClient();
    client.setParametersConverter(new MyCustomConverter());
    return client;
    }
    java
  • SAML 2.0 - Spring Security SAML 2.0 服务提供者接口的非版本化 OpenSAML 实现已被弃用,建议使用版本化的实现。例如,OpenSamlAuthenticationTokenConverter 现在被 OpenSaml4AuthenticationTokenConverterOpenSaml5AuthenticationTokenConverter 取代。如果你正在构建这些已弃用的版本之一,请将其替换为与你使用的 OpenSAML 版本相对应的实现。

  • SAML 2.0 - 围绕 AssertingPartyDetails 的方法已被弃用,建议使用等效的 AssertingPartyMetadata 接口方法。

  • LDAP - DistinguishedName 的使用已被弃用,以便与 Spring LDAP 的弃用保持一致。

一次性令牌登录

通行密钥

Spring Security 现在支持 Passkeys

方法安全

  • 所有方法安全注解现在都支持Spring Framework 的 @AliasFor

  • @AuthenticationPrincipal@CurrentSecurityContext 现在支持注解模板

    这意味着你现在可以像这样使用 Spring 的元注解支持:

    @Target(TargetType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @AuthenticationPrincipal("claims['{claim}']")
    @interface CurrentUsername {
    String claim() default "sub";
    }

    // ...

    @GetMapping
    public String method(@CurrentUsername("username") String username) {
    // ...
    }
    java
  • 进行了多项改进以将 Security 的注解搜索与 AbstractFallbackMethodSecurityMetadataSource 的算法对齐。这有助于从早期版本的 Spring Security 迁移。

  • 原生应用程序现在可以使用 @AuthorizeReturnObject

  • 原生应用程序现在可以在 @PreAuthorize@PostAuthorize引用 beans

  • SecurityAnnotationScanners 提供了一个便捷的 API,用于扫描 Security 注解,并将 Security 的选择和模板功能添加到自定义注解中。

OAuth 2.0

  • oauth2Login() 现在接受 OAuth2AuthorizationRequestResolver 作为 @Bean

  • ClientRegistrations 现在支持外部获取的配置

  • 在响应式 oauth2Login() 的 DSL 中新增了 loginPage()

  • OIDC 后台通道支持现在接受 类型为 logout+jwt 的注销令牌

  • RestClient 现在可以通过 OAuth2ClientHttpRequestInterceptor 进行配置,以发起受保护资源的请求

  • 新增了基于 RestClientOAuth2AccessTokenResponseClient 实现,以便更一致地配置访问令牌请求。

    要启用 RestClient 支持,只需为每种授权类型发布一个 bean,如下例所示:

    @Configuration
    public class SecurityConfig {

    @Bean
    public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> authorizationCodeAccessTokenResponseClient() {
    return new RestClientAuthorizationCodeTokenResponseClient();
    }

    @Bean
    public OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> refreshTokenAccessTokenResponseClient() {
    return new RestClientRefreshTokenTokenResponseClient();
    }

    @Bean
    public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsAccessTokenResponseClient() {
    return new RestClientClientCredentialsTokenResponseClient();
    }

    @Bean
    public OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> jwtBearerAccessTokenResponseClient() {
    return new RestClientJwtBearerTokenResponseClient();
    }

    @Bean
    public OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> tokenExchangeAccessTokenResponseClient() {
    return new RestClientTokenExchangeTokenResponseClient();
    }

    }
    java
  • 令牌交换现在支持刷新令牌

SAML 2.0

  • 添加了 OpenSAML 5 支持。现在你可以使用 OpenSAML 4 或 OpenSAML 5;默认情况下,Spring Security 会根据你的 classpath 自动选择合适的实现。

  • 简化了使用 EntityID 作为 registrationId 的方式。

    一种常见的模式是通过 entityID 来识别断言方。在之前的版本中,这需要直接配置 OpenSamlAuthenticationRequestResolver。现在,请求解析器默认会在路径中查找 registrationId,同时也会将其作为请求参数进行查找。这使得你可以使用 RelyingPartyRegistrationsOpenSaml4/5AssertingPartyMetadataRepository,而无需修改 registrationId 值或自定义请求解析器。

    相关地,你现在可以配置 authenticationRequestUri包含查询参数

  • 现在可以根据元数据的过期时间在后台刷新断言方。

    例如,你现在可以使用 OpenSaml5AssertingPartyMetadataRepository 来实现:

    @Component
    public class RefreshableRelyingPartyRegistrationRepository implements IterableRelyingPartyRegistrationRepository {
    private final AssertingPartyMetadataRepository assertingParties = OpenSaml5AssertingPartyMetadataRepository
    .fromTrustedMetadataLocation("https://idp.example.org").build();

    @Override
    public RelyingPartyRegistration findByRegistrationId(String registrationId) {
    AssertingPartyMetadata assertingParty = this.assertingParties.findByEntityId(registrationId);
    return RelyingPartyRegistration.withAssertingPartyMetadata(assertingParty)
    // 依赖方配置
    .build();
    }

    // ...
    }
    java

    该实现还支持元数据签名的验证。

  • 你现在可以对依赖方元数据进行签名

  • RelyingPartyRegistrationRepository 的结果现在可以缓存。如果你希望在应用启动后延迟加载注册值,这将非常有用。如果你希望通过 Spring Cache 控制元数据的刷新时间,这也很有帮助。

  • 为了与 SAML 2.0 标准保持一致,元数据端点现在使用 application/samlmetadata+xml MIME 类型

Web

  • CSRF BREACH 令牌现在更加一致

  • Remember Me cookie 现在更加可定制

  • 安全过滤器链现在能够发现更多的无效配置。例如,在任意请求过滤器链之后声明的过滤器链是无效的,因为它永远不会被调用:

    @Bean
    @Order(0)
    SecurityFilterChain api(HttpSecurity http) throws Exception {
    http
    // 隐式的 securityMatcher("/**")
    .authorizeHttpRequests(...)
    .httpBasic(...)

    return http.build();
    }

    @Bean
    @Order(1)
    SecurityFilterChain app(HttpSecurity http) throws Exception {
    http
    .securityMatcher("/app/**")
    .authorizeHttpRequests(...)
    .formLogin(...)

    return http.build();
    }
    java

    你可以在相关工单中了解更多信息。

  • ServerHttpSecurity 现在将 ServerWebExchangeFirewall 作为 @Bean 使用

可观测性

可观测性现在支持单独切换授权、认证和请求观测。例如,要关闭过滤器链观测,你可以发布一个像这样的 @Bean

@Bean
SecurityObservationSettings allSpringSecurityObservations() {
return SecurityObservationSettings.withDefaults()
.shouldObserveFilterChains(false).build();
}
java

Kotlin

Acl