Session Management 迁移

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

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

要求明确保存 SecurityContextRepository

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

在 Spring Security 6 中,默认行为是 SecurityContextHolderFilter 只从 SecurityContextRepository 读取 SecurityContext 并将其填充到 SecurityContextHolder 中。现在,如果用户希望 SecurityContext 在不同请求之间持续存在,他们必须明确地将 SecurityContextSecurityContextRepository 一起保存。这消除了歧义,并通过仅在必要时要求写入 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中,默认的 SecurityContextRepositoryHttpSessionSecurityContextRepository

在 Spring Security 6 中,默认的 SecurityContextRepositoryDelegatingSecurityContextRepository。如果你配置 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"/>