Spring Security 6.4 的新特性
Spring Security 6.4 提供了许多新功能。以下是该版本的主要亮点,或者您可以查看发布说明以获取每个功能和错误修复的详细列表。
弃用通知
随着我们即将迎来 Spring Security 7,及时了解弃用内容变得尤为重要。因此,本节指出了 6.4 版本中的弃用内容。
-
方法安全 -
AuthorizationManager#check
已被弃用,建议使用AuthorizationManager#authorize
。这主要是为了让返回类型可以是一个接口而不是具体的类。如果你正在调用AuthorizationManager#check
,请改为调用AuthorizationManager#authorize
。与此相关的是,接受
AuthorizationDecision
的AuthorizationEventPublisher#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 -
DefaultAuthorizationCodeTokenResponseClient
、DefaultClientCredentialsTokenResponseClient
、DefaultJwtBearerTokenResponseClient
、DefaultPasswordTokenResponseClient
、DefaultRefreshTokenTokenResponseClient
和DefaultTokenExchangeTokenResponseClient
已被弃用,建议使用它们的RestClient
等效实现。与此相关的是,
JwtBearerGrantRequestEntityConverter
、OAuth2AuthorizationCodeGrantRequestEntityConverter
、OAuth2ClientCredentialsGrantRequestEntityConverter
、OAuth2PasswordGrantRequestEntityConverter
、OAuth2RefreshTokenGrantRequestEntityConverter
已被弃用,建议使用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;
}这个配置已被弃用,因为它使用了
DefaultAuthorizationCodeTokenResponseClient
和OAuth2AuthorizationCodeGrantRequestEntityConverter
。推荐的配置现在是: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;
} -
SAML 2.0 - Spring Security SAML 2.0 服务提供者接口的非版本化 OpenSAML 实现已被弃用,建议使用版本化的实现。例如,
OpenSamlAuthenticationTokenConverter
现在被OpenSaml4AuthenticationTokenConverter
和OpenSaml5AuthenticationTokenConverter
取代。如果你正在构建这些已弃用的版本之一,请将其替换为与你使用的 OpenSAML 版本相对应的实现。 -
SAML 2.0 - 围绕
AssertingPartyDetails
的方法已被弃用,建议使用等效的AssertingPartyMetadata
接口方法。 -
LDAP -
DistinguishedName
的使用已被弃用,以便与 Spring LDAP 的弃用保持一致。
一次性令牌登录
通行密钥
Spring Security 现在支持 Passkeys。
方法安全
-
@AuthenticationPrincipal
和@CurrentSecurityContext
现在支持注解模板。这意味着你现在可以像这样使用 Spring 的元注解支持:
- Java
- Kotlin
@Target(TargetType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@AuthenticationPrincipal("claims['{claim}']")
@interface CurrentUsername {
String claim() default "sub";
}
// ...
@GetMapping
public String method(@CurrentUsername("username") String username) {
// ...
}annotation CurrentUsername(val claim: String = "sub")
// ...
@GetMapping
fun method(@CurrentUsername("username") val username: String): String {
// ...
} -
进行了多项改进以将 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
进行配置,以发起受保护资源的请求 -
新增了基于
RestClient
的OAuth2AccessTokenResponseClient
实现,以便更一致地配置访问令牌请求。要启用
RestClient
支持,只需为每种授权类型发布一个 bean,如下例所示:- Java
- Kotlin
@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();
}
}@Configuration
class SecurityConfig {
@Bean
fun authorizationCodeAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> {
return RestClientAuthorizationCodeTokenResponseClient()
}
@Bean
fun refreshTokenAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> {
return RestClientRefreshTokenTokenResponseClient()
}
@Bean
fun clientCredentialsAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> {
return RestClientClientCredentialsTokenResponseClient()
}
@Bean
fun jwtBearerAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> {
return RestClientJwtBearerTokenResponseClient()
}
@Bean
fun tokenExchangeAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> {
return RestClientTokenExchangeTokenResponseClient()
}
} -
令牌交换现在支持刷新令牌
SAML 2.0
-
添加了 OpenSAML 5 支持。现在你可以使用 OpenSAML 4 或 OpenSAML 5;默认情况下,Spring Security 会根据你的 classpath 自动选择合适的实现。
-
简化了使用 EntityID 作为
registrationId
的方式。一种常见的模式是通过
entityID
来识别断言方。在之前的版本中,这需要直接配置OpenSamlAuthenticationRequestResolver
。现在,请求解析器默认会在路径中查找registrationId
,同时也会将其作为请求参数进行查找。这使得你可以使用RelyingPartyRegistrations
或OpenSaml4/5AssertingPartyMetadataRepository
,而无需修改registrationId
值或自定义请求解析器。相关地,你现在可以配置
authenticationRequestUri
以包含查询参数。 -
现在可以根据元数据的过期时间在后台刷新断言方。
例如,你现在可以使用 OpenSaml5AssertingPartyMetadataRepository 来实现:
- Java
- Kotlin
@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();
}
// ...
}@Component
open class RefreshableRelyingPartyRegistrationRepository: IterableRelyingPartyRegistrationRepository {
private val assertingParties: AssertingPartyMetadataRepository = OpenSaml5AssertingPartyMetadataRepository
.fromTrustedMetadataLocation("https://idp.example.org").build()
override fun findByRegistrationId(String registrationId): RelyingPartyRegistration {
val assertingParty = this.assertingParties.findByEntityId(registrationId)
return RelyingPartyRegistration.withAssertingPartyMetadata(assertingParty)
// 依赖方配置
.build()
}
// ...
}该实现还支持元数据签名的验证。
-
你现在可以对依赖方元数据进行签名。
-
RelyingPartyRegistrationRepository
的结果现在可以缓存。如果你希望在应用启动后延迟加载注册值,这将非常有用。如果你希望通过 Spring Cache 控制元数据的刷新时间,这也很有帮助。 -
为了与 SAML 2.0 标准保持一致,元数据端点现在使用 application/samlmetadata+xml MIME 类型。
Web
-
CSRF BREACH 令牌现在更加一致
-
Remember Me cookie 现在更加可定制
-
安全过滤器链现在能够发现更多的无效配置。例如,在任意请求过滤器链之后声明的过滤器链是无效的,因为它永远不会被调用:
- Java
- Kotlin
@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();
}@Bean
@Order(0)
fun api(val http: HttpSecurity): SecurityFilterChain {
http {
authorizeHttpRequests {
// ...
}
}
return http.build()
}
@Bean
@Order(1)
fun app(val http: HttpSecurity): SecurityFilterChain {
http {
securityMatcher("/app/**")
authorizeHttpRequests {
// ...
}
}
return http.build()
}你可以在相关工单中了解更多信息。
-
ServerHttpSecurity
现在将 ServerWebExchangeFirewall 作为 @Bean 使用
可观测性
可观测性现在支持单独切换授权、认证和请求观测。例如,要关闭过滤器链观测,你可以发布一个像这样的 @Bean
:
- Java
- Kotlin
@Bean
SecurityObservationSettings allSpringSecurityObservations() {
return SecurityObservationSettings.withDefaults()
.shouldObserveFilterChains(false).build();
}
@Bean
fun allSpringSecurityObservations(): SecurityObservationSettings {
return SecurityObservationSettings.builder()
.shouldObserveFilterChains(false).build()
}
Kotlin
-
Kotlin DSL 现在支持 SAML 2.0、GrantedAuthorityDefaults 和 RoleHierarchy 的
@Bean
。 -
Kotlin 中的
@PreFilter
和@PostFilter
现已支持。 -
Kotlin Reactive DSL 现在支持 SecurityContextRepository。
Acl
AclAuthorizationStrategyImpl
现在支持 RoleHierarchy