对于最新的稳定版本,请使用 Spring Security 6.4.3spring-doc.cadn.net.cn

会话管理迁移

需要显式保存 SecurityContextRepository

在 Spring Security 5 中,默认行为是针对SecurityContext以自动保存到SecurityContextRepository使用SecurityContextPersistenceFilter. 保存必须在HttpServletResponse正在提交和之前SecurityContextPersistenceFilter. 遗憾的是,自动持久化SecurityContext在请求完成之前(即在提交HttpServletResponse). 跟踪状态以确定是否需要保存也很复杂,这会导致对SecurityContextRepository(即HttpSession)。spring-doc.cadn.net.cn

在 Spring Security 6 中,默认行为是SecurityContextHolderFilter只会读取SecurityContextSecurityContextRepository并将其填充到SecurityContextHolder. 用户现在必须显式保存SecurityContext使用SecurityContextRepository如果他们想要SecurityContext以在请求之间持续存在。 这消除了歧义并提高了性能,因为只需要写入SecurityContextRepository(即HttpSession) 时。spring-doc.cadn.net.cn

清除上下文时(例如在注销期间),也需要保存上下文。请参阅此部分以了解更多信息spring-doc.cadn.net.cn

要选择新的 Spring Security 6 默认值,可以使用以下配置。spring-doc.cadn.net.cn

显式保存 SecurityContext
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还会保存SecurityContextSecurityContextRepository是否应在请求之间持久保存。spring-doc.cadn.net.cn

例如,以下代码:spring-doc.cadn.net.cn

设置SecurityContextHolderSecurityContextPersistenceFilter
SecurityContextHolder.setContext(securityContext);
SecurityContextHolder.setContext(securityContext)
设置SecurityContextHolderSecurityContextHolderFilter
SecurityContextHolder.setContext(securityContext);
securityContextRepository.saveContext(securityContext, httpServletRequest, httpServletResponse);
SecurityContextHolder.setContext(securityContext)
securityContextRepository.saveContext(securityContext, httpServletRequest, httpServletResponse)

改变HttpSessionSecurityContextRepositoryDelegatingSecurityContextRepository

在 Spring Security 5 中,默认的SecurityContextRepositoryHttpSessionSecurityContextRepository.spring-doc.cadn.net.cn

在 Spring Security 6 中,默认的SecurityContextRepositoryDelegatingSecurityContextRepository. 要选择新的 Spring Security 6 默认值,可以使用以下配置。spring-doc.cadn.net.cn

使用 6.0 默认值配置 SecurityContextRepository
@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>

如果您已在使用HttpSessionSecurityContextRepository,您应该将其替换为您在上面的示例中选择的实现,以确保它与RequestAttributeSecurityContextRepository.spring-doc.cadn.net.cn

地址SecurityContextRepository弃用

在 Spring Security 5.7 中,添加了一个新方法SecurityContextRepository替换为签名:spring-doc.cadn.net.cn

Supplier<SecurityContext> loadContext(HttpServletRequest request)

随着DelegatingSecurityContextRepository在 Spring Security 5.8 中,该方法已被弃用,取而代之的是具有签名的新方法:spring-doc.cadn.net.cn

DeferredSecurityContext loadDeferredContext(HttpServletRequest request)

在 Spring Security 6 中,已删除弃用的方法。 如果您已实施SecurityContextRepository自己,并添加了loadContext(request)方法,你可以通过删除该方法的实现并改为实现新方法来为 Spring Security 6 做准备。spring-doc.cadn.net.cn

要开始实现新方法,请使用以下示例提供DeferredSecurityContext:spring-doc.cadn.net.cn

提供DeferredSecurityContext
@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 中,默认行为是在每个请求上查询保存的请求。 这意味着,在典型设置中,为了使用RequestCacheHttpSession在每个请求中查询。spring-doc.cadn.net.cn

在 Spring Security 6 中,默认值是RequestCache如果 HTTP 参数continue已定义。 这允许 Spring Security 避免不必要地读取HttpSession使用RequestCache.spring-doc.cadn.net.cn

在 Spring Security 5 中,默认使用HttpSessionRequestCache将在每个请求中查询缓存的请求。 如果您没有覆盖默认值(即使用NullRequestCache),则以下配置可用于在 Spring Security 5.8 中显式选择加入 Spring Security 6 行为:spring-doc.cadn.net.cn

RequestCache仅在以下情况下检查保存的请求continue参数存在
@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-doc.cadn.net.cn

在 Spring Security 6 中,默认情况下,身份验证机制本身必须调用SessionAuthenticationStrategy. 这意味着无需检测何时Authentication已完成,因此HttpSession不需要为每个请求读取。spring-doc.cadn.net.cn

要选择新的 Spring Security 6 默认值,可以使用以下配置。spring-doc.cadn.net.cn

需要显式SessionAuthenticationStrategy调用
@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 默认值:spring-doc.cadn.net.cn

显式使用 Spring Security 5.8 的默认值SessionAuthenticationStrategy
@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>