对于最新的稳定版本,请使用 Spring Security 6.4.3! |
会话管理迁移
需要显式保存 SecurityContextRepository
在 Spring Security 5 中,默认行为是针对SecurityContext
以自动保存到SecurityContextRepository
使用SecurityContextPersistenceFilter
.
保存必须在HttpServletResponse
正在提交和之前SecurityContextPersistenceFilter
.
遗憾的是,自动持久化SecurityContext
在请求完成之前(即在提交HttpServletResponse
).
跟踪状态以确定是否需要保存也很复杂,这会导致对SecurityContextRepository
(即HttpSession
)。
在 Spring Security 6 中,默认行为是SecurityContextHolderFilter
只会读取SecurityContext
从SecurityContextRepository
并将其填充到SecurityContextHolder
.
用户现在必须显式保存SecurityContext
使用SecurityContextRepository
如果他们想要SecurityContext
以在请求之间持续存在。
这消除了歧义并提高了性能,因为只需要写入SecurityContextRepository
(即HttpSession
) 时。
清除上下文时(例如在注销期间),也需要保存上下文。请参阅此部分以了解更多信息。 |
要选择新的 Spring Security 6 默认值,可以使用以下配置。
-
Java
-
Kotlin
-
XML
public SecurityFilterChain filterChain(HttpSecurity http) {
http
// ...
.securityContext((securityContext) -> securityContext
.requireExplicitSave(true)
);
return http.build();
}
@Bean
open fun springSecurity(http: HttpSecurity): SecurityFilterChain {
http {
securityContext {
requireExplicitSave = true
}
}
return http.build()
}
<http security-context-explicit-save="true">
<!-- ... -->
</http>
使用配置时,将SecurityContextHolder
替换为SecurityContext
还会保存SecurityContext
到SecurityContextRepository
是否应在请求之间持久保存。
例如,以下代码:
SecurityContextHolder
跟SecurityContextPersistenceFilter
-
Java
-
Kotlin
SecurityContextHolder.setContext(securityContext);
SecurityContextHolder.setContext(securityContext)
应替换为
SecurityContextHolder
跟SecurityContextHolderFilter
-
Java
-
Kotlin
SecurityContextHolder.setContext(securityContext);
securityContextRepository.saveContext(securityContext, httpServletRequest, httpServletResponse);
SecurityContextHolder.setContext(securityContext)
securityContextRepository.saveContext(securityContext, httpServletRequest, httpServletResponse)
改变HttpSessionSecurityContextRepository
自DelegatingSecurityContextRepository
在 Spring Security 5 中,默认的SecurityContextRepository
是HttpSessionSecurityContextRepository
.
在 Spring Security 6 中,默认的SecurityContextRepository
是DelegatingSecurityContextRepository
.
要选择新的 Spring Security 6 默认值,可以使用以下配置。
-
Java
-
Kotlin
-
XML
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.securityContext((securityContext) -> securityContext
.securityContextRepository(new DelegatingSecurityContextRepository(
new RequestAttributeSecurityContextRepository(),
new HttpSessionSecurityContextRepository()
))
);
return http.build();
}
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
// ...
securityContext {
securityContextRepository = DelegatingSecurityContextRepository(
RequestAttributeSecurityContextRepository(),
HttpSessionSecurityContextRepository()
)
}
}
return http.build()
}
<http security-context-repository-ref="contextRepository">
<!-- ... -->
</http>
<bean name="contextRepository"
class="org.springframework.security.web.context.DelegatingSecurityContextRepository">
<constructor-arg>
<bean class="org.springframework.security.web.context.RequestAttributeSecurityContextRepository" />
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.web.context.HttpSessionSecurityContextRepository" />
</constructor-arg>
</bean>
如果您已在使用 |
地址SecurityContextRepository
弃用
在 Spring Security 5.7 中,添加了一个新方法SecurityContextRepository
替换为签名:
Supplier<SecurityContext> loadContext(HttpServletRequest request)
随着DelegatingSecurityContextRepository
在 Spring Security 5.8 中,该方法已被弃用,取而代之的是具有签名的新方法:
DeferredSecurityContext loadDeferredContext(HttpServletRequest request)
在 Spring Security 6 中,已删除弃用的方法。
如果您已实施SecurityContextRepository
自己,并添加了loadContext(request)
方法,你可以通过删除该方法的实现并改为实现新方法来为 Spring Security 6 做准备。
要开始实现新方法,请使用以下示例提供DeferredSecurityContext
:
DeferredSecurityContext
-
Java
-
Kotlin
@Override
public DeferredSecurityContext loadDeferredContext(HttpServletRequest request) {
return new DeferredSecurityContext() {
private SecurityContext securityContext;
private boolean isGenerated;
@Override
public SecurityContext get() {
if (this.securityContext == null) {
this.securityContext = getContextOrNull(request);
if (this.securityContext == null) {
SecurityContextHolderStrategy strategy = SecurityContextHolder.getContextHolderStrategy();
this.securityContext = strategy.createEmptyContext();
this.isGenerated = true;
}
}
return this.securityContext;
}
@Override
public boolean isGenerated() {
get();
return this.isGenerated;
}
};
}
override fun loadDeferredContext(request: HttpServletRequest): DeferredSecurityContext {
return object : DeferredSecurityContext {
private var securityContext: SecurityContext? = null
private var isGenerated = false
override fun get(): SecurityContext {
if (securityContext == null) {
securityContext = getContextOrNull(request)
?: SecurityContextHolder.getContextHolderStrategy().createEmptyContext()
.also { isGenerated = true }
}
return securityContext!!
}
override fun isGenerated(): Boolean {
get()
return isGenerated
}
}
}
优化查询RequestCache
在 Spring Security 5 中,默认行为是在每个请求上查询保存的请求。
这意味着,在典型设置中,为了使用RequestCache
这HttpSession
在每个请求中查询。
在 Spring Security 6 中,默认值是RequestCache
如果 HTTP 参数continue
已定义。
这允许 Spring Security 避免不必要地读取HttpSession
使用RequestCache
.
在 Spring Security 5 中,默认使用HttpSessionRequestCache
将在每个请求中查询缓存的请求。
如果您没有覆盖默认值(即使用NullRequestCache
),则以下配置可用于在 Spring Security 5.8 中显式选择加入 Spring Security 6 行为:
RequestCache
仅在以下情况下检查保存的请求continue
参数存在-
Java
-
Kotlin
-
XML
@Bean
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
HttpSessionRequestCache requestCache = new HttpSessionRequestCache();
requestCache.setMatchingRequestParameterName("continue");
http
// ...
.requestCache((cache) -> cache
.requestCache(requestCache)
);
return http.build();
}
@Bean
open fun springSecurity(http: HttpSecurity): SecurityFilterChain {
val httpRequestCache = HttpSessionRequestCache()
httpRequestCache.setMatchingRequestParameterName("continue")
http {
requestCache {
requestCache = httpRequestCache
}
}
return http.build()
}
<http auto-config="true">
<!-- ... -->
<request-cache ref="requestCache"/>
</http>
<b:bean id="requestCache" class="org.springframework.security.web.savedrequest.HttpSessionRequestCache"
p:matchingRequestParameterName="continue"/>
需要显式调用 SessionAuthenticationStrategy
在 Spring Security 5 中,默认配置依赖于SessionManagementFilter
要检测用户是否刚刚进行身份验证并调用SessionAuthenticationStrategy
.
这样做的问题在于,这意味着在典型设置中,HttpSession
必须为每个请求读取。
在 Spring Security 6 中,默认情况下,身份验证机制本身必须调用SessionAuthenticationStrategy
.
这意味着无需检测何时Authentication
已完成,因此HttpSession
不需要为每个请求读取。
要选择新的 Spring Security 6 默认值,可以使用以下配置。
SessionAuthenticationStrategy
调用-
Java
-
Kotlin
-
XML
@Bean
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
http
// ...
.sessionManagement((sessions) -> sessions
.requireExplicitAuthenticationStrategy(true)
);
return http.build();
}
@Bean
open fun springSecurity(http: HttpSecurity): SecurityFilterChain {
http {
sessionManagement {
requireExplicitAuthenticationStrategy = true
}
}
return http.build()
}
<http>
<!-- ... -->
<session-management authentication-strategy-explicit-invocation="true"/>
</http>
如果这会破坏您的应用程序,那么您可以使用以下配置显式选择加入 5.8 默认值:
SessionAuthenticationStrategy
-
Java
-
Kotlin
-
XML
@Bean
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
http
// ...
.sessionManagement((sessions) -> sessions
.requireExplicitAuthenticationStrategy(false)
);
return http.build();
}
@Bean
open fun springSecurity(http: HttpSecurity): SecurityFilterChain {
http {
sessionManagement {
requireExplicitAuthenticationStrategy = false
}
}
return http.build()
}
<http>
<!-- ... -->
<session-management authentication-strategy-explicit-invocation="false"/>
</http>