| 对于最新的稳定版本,请使用 Spring Security 6.3.3! | 
| 对于最新的稳定版本,请使用 Spring Security 6.3.3! | 
GET / HTTP/1.1
Host: example.com
Cookie: SESSION=91470ce0-3f3c-455b-b7ad-079b02290f7bHTTP/1.1 302 Found
Location: /login用户提交其用户名和密码。
POST /login HTTP/1.1
Host: example.com
Cookie: SESSION=91470ce0-3f3c-455b-b7ad-079b02290f7b
username=user&password=password&_csrf=35942e65-a172-4cd4-a1d4-d16a51147b3e在对用户进行身份验证后,用户会与新的会话 ID 相关联,以防止会话固定攻击。
HTTP/1.1 302 Found
Location: /
Set-Cookie: SESSION=4c66e474-3f5a-43ed-8e48-cc1d8cb1d1c8; Path=/; HttpOnly; SameSite=Lax后续请求包括会话 cookie,该 cookie 用于在会话的剩余时间内对用户进行身份验证。
GET / HTTP/1.1
Host: example.com
Cookie: SESSION=4c66e474-3f5a-43ed-8e48-cc1d8cb1d1c8SecurityContextRepository 存储库
在 Spring Security 中,用户与未来请求的关联是使用SecurityContextRepository进行的。
的默认实现是DelegatingSecurityContextRepository,它委托给以下内容:SecurityContextRepository
HttpSessionSecurityContextRepository
HttpSessionSecurityContextRepository 将 SecurityContext 与 .
如果用户希望以其他方式将用户与后续请求关联,或者根本不关联,则可以替换为其他实现。HttpSessionHttpSessionSecurityContextRepositorySecurityContextRepository
NullSecurityContext存储库
如果不希望将 关联到(即使用 OAuth 进行身份验证时),则 NullSecurityContextRepository 是一个不执行任何操作的实现。SecurityContextHttpSessionSecurityContextRepository
RequestAttributeSecurityContextRepository
RequestAttributeSecurityContextRepository 将 as a 请求属性保存为 request,以确保 可用于跨调度类型发生的单个请求,这些请求可能会清除 .SecurityContextSecurityContextSecurityContext
例如,假设客户端发出请求,经过身份验证,然后发生错误。
根据 servlet 容器的实现,该错误意味着清除了已建立的任何内容,然后进行错误分派。
进行错误分派时,没有建立。
这意味着错误页面无法使用 for authorization 或显示当前用户,除非以某种方式保留 。SecurityContextSecurityContextSecurityContextSecurityContext
- 
Java 
- 
XML 
public SecurityFilterChain filterChain(HttpSecurity http) {
	http
		// ...
		.securityContext((securityContext) -> securityContext
			.securityContextRepository(new RequestAttributeSecurityContextRepository())
		);
	return http.build();
}<http security-context-repository-ref="contextRepository">
	<!-- ... -->
</http>
<b:bean name="contextRepository"
	class="org.springframework.security.web.context.RequestAttributeSecurityContextRepository" />委托SecurityContextRepository
DelegatingSecurityContextRepository 将 保存到多个委托,并允许按指定顺序从任何委托中检索。SecurityContextSecurityContextRepository
最有用的安排是通过以下示例配置的,该示例允许同时使用RequestAttributeSecurityContextRepository和HttpSessionSecurityContextRepository。
- 
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>| 在 Spring Security 6 中,上面显示的示例是默认配置。 | 
| 在 Spring Security 6 中,上面显示的示例是默认配置。 | 
SecurityContextPersistenceFilter
SecurityContextPersistenceFilter负责使用SecurityContextRepository在请求之间持久化。SecurityContext
 
 在运行应用程序的其余部分之前,从 加载 并将其设置在 .
在运行应用程序的其余部分之前,从 加载 并将其设置在 .SecurityContextPersistenceFilterSecurityContextSecurityContextRepositorySecurityContextHolder
 接下来,运行应用程序。
接下来,运行应用程序。
 最后,如果 the 已更改,我们使用 保存 。
这意味着,当使用 时,只需设置 即可确保使用 保留 。
最后,如果 the 已更改,我们使用 保存 。
这意味着,当使用 时,只需设置 即可确保使用 保留 。SecurityContextSecurityContextSecurityContextPersistenceRepositorySecurityContextPersistenceFilterSecurityContextHolderSecurityContextSecurityContextRepository
在某些情况下,在方法完成之前,会提交响应并将其写入客户端。
例如,如果将重定向发送到客户端,则响应会立即写回客户端。
这意味着在步骤 3 中无法建立 ,因为会话 ID 无法包含在已编写的响应中。
可能发生的另一种情况是,如果客户端身份验证成功,则响应在完成之前提交,并且客户端在完成之前发出第二个请求,则第二个请求中可能会出现错误的身份验证。SecurityContextPersistenceFilterHttpSessionSecurityContextPersistenceFilterSecurityContextPersistenceFilter
为避免这些问题,将 the 和 the 包装起来以检测 the 是否已更改,如果是,则在提交响应之前保存 。SecurityContextPersistenceFilterHttpServletRequestHttpServletResponseSecurityContextSecurityContext
SecurityContextHolderFilter
SecurityContextHolderFilter负责使用SecurityContextRepository加载请求之间的请求。SecurityContext
 
 在运行应用程序的其余部分之前,从 加载 并将其设置在 .
在运行应用程序的其余部分之前,从 加载 并将其设置在 .SecurityContextHolderFilterSecurityContextSecurityContextRepositorySecurityContextHolder
 接下来,运行应用程序。
接下来,运行应用程序。
与 SecurityContextPersistenceFilter 不同,它只加载它不会保存 .
这意味着在使用 时,需要显式保存 。SecurityContextHolderFilterSecurityContextSecurityContextSecurityContextHolderFilterSecurityContext
- 
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>使用配置时,如果应在请求之间保留,则任何使用 a 设置 the 的代码也必须保存 to。SecurityContextHolderSecurityContextSecurityContextSecurityContextRepository
例如,以下代码:
SecurityContextHolderSecurityContextPersistenceFilter- 
Java 
- 
Kotlin 
SecurityContextHolder.setContext(securityContext);SecurityContextHolder.setContext(securityContext)应替换为
SecurityContextHolderSecurityContextHolderFilter- 
Java 
- 
Kotlin 
SecurityContextHolder.setContext(securityContext);
securityContextRepository.saveContext(securityContext, httpServletRequest, httpServletResponse);SecurityContextHolder.setContext(securityContext)
securityContextRepository.saveContext(securityContext, httpServletRequest, httpServletResponse)