Session Management 迁移

本站(springdoc.cn)中的内容来源于 spring.io ,原始版权归属于 spring.io。由 springboot.io - Spring Boot中文社区 进行翻译,整理。可供个人学习、研究,未经许可,不得进行任何转载、商用或与之相关的行为。 商标声明:Spring 是 Pivotal Software, Inc. 在美国以及其他国家的商标。

下面的步骤涉及到如何完成迁移会话管理支持。

要求明确保存 SecurityContextRepository

在Spring Security 5中,默认行为是使用 SecurityContextPersistenceFilter 将 SecurityContext 自动保存到 SecurityContextRepository 中。保存必须在 HttpServletResponse 被提交之前和 SecurityContextPersistenceFilter 之前进行。不幸的是,当 SecurityContext 的自动持久化在请求完成之前(即在提交 HttpServletResponse 之前)完成时,会让用户感到惊讶。跟踪状态以确定是否需要保存也很复杂,有时会导致对 SecurityContextRepository(即 HttpSession)进行不必要的写入。

在 Spring Security 6 中,默认行为是 SecurityContextHolderFilter 只从 SecurityContextRepository 读取 SecurityContext 并将其填充到 SecurityContextHolder 中。现在,如果用户希望 SecurityContext 在不同请求之间持续存在,他们必须明确地将 SecurityContext 与 SecurityContextRepository 一起保存。这消除了歧义,并通过仅在必要时要求写入 SecurityContextRepository(即 HttpSession)来提高性能。

如果你明确选择加入Spring Security 6的新默认值,可以删除以下配置以接受Spring Security 6的默认值。

Example 1. Explicit Saving of SecurityContext
Java
public SecurityFilterChain filterChain(HttpSecurity http) {
	http
		// ...
		.securityContext((securityContext) -> securityContext
			.requireExplicitSave(true)
		);
	return http.build();
}
Kotlin
@Bean
open fun springSecurity(http: HttpSecurity): SecurityFilterChain {
    http {
        securityContext {
            requireExplicitSave = true
        }
    }
    return http.build()
}
XML
<http security-context-explicit-save="true">
	<!-- ... -->
</http>

在使用该配置时,重要的是任何用 SecurityContextHolder 设置 SecurityContext 的代码也要将 SecurityContext 保存到 SecurityContextRepository 中,如果它应该在不同的请求之间持续存在。

例如,下面的代码。

Example 2. Setting SecurityContextHolder with SecurityContextPersistenceFilter
Java
SecurityContextHolder.setContext(securityContext);
Kotlin
SecurityContextHolder.setContext(securityContext)

should be replaced with

Example 3. Setting SecurityContextHolder with SecurityContextHolderFilter
Java
SecurityContextHolder.setContext(securityContext);
securityContextRepository.saveContext(securityContext, httpServletRequest, httpServletResponse);
Kotlin
SecurityContextHolder.setContext(securityContext)
securityContextRepository.saveContext(securityContext, httpServletRequest, httpServletResponse)

== 多个 SecurityContextRepository

在 Spring Security 5中,默认的 SecurityContextRepository 是 HttpSessionSecurityContextRepository。

在 Spring Security 6 中,默认的 SecurityContextRepository 是 DelegatingSecurityContextRepository。如果你配置 SecurityContextRepository 的目的只是为了更新到6.0,你可以完全删除它。

== SecurityContextRepository 的弃用

对于这种废弃,没有进一步的迁移步骤。

== 优化 RequestCache 查询

在Spring Security 5中,默认行为是在每个请求中查询 已保存的请求。这意味着在一个典型的设置中,为了使用 RequestCache,每次请求都要查询 HttpSession。

在Spring Security 6中,默认情况下,只有在定义了 HTTP 参数 continue 的情况下, RequestCache 才会被查询到缓存的请求。这使得 Spring Security 可以避免不必要地用 RequestCache 读取 HttpSession。

在Spring Security 5中,默认是使用 HttpSessionRequestCache,它将在每个请求中被查询到一个缓存的请求。如果你没有覆盖默认值(即使用 NullRequestCache),那么可以使用以下配置在Spring Security 5.8中明确选择Spring Security 6的行为。

Java
@Bean
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
	HttpSessionRequestCache requestCache = new HttpSessionRequestCache();
	requestCache.setMatchingRequestParameterName("continue");
	http
		// ...
		.requestCache((cache) -> cache
			.requestCache(requestCache)
		);
	return http.build();
}
Kotlin
@Bean
open fun springSecurity(http: HttpSecurity): SecurityFilterChain {
    val httpRequestCache = HttpSessionRequestCache()
    httpRequestCache.setMatchingRequestParameterName("continue")
    http {
        requestCache {
            requestCache = httpRequestCache
        }
    }
    return http.build()
}
XML
<http auto-config="true">
	<!-- ... -->
	<request-cache ref="requestCache"/>
</http>

<b:bean id="requestCache" class="org.springframework.security.web.savedrequest.HttpSessionRequestCache"
	p:matchingRequestParameterName="continue"/>