对于最新的稳定版本,请使用 Spring Security 6.5.3! |
持久身份验证
GET / HTTP/1.1
Host: example.com
Cookie: SESSION=91470ce0-3f3c-455b-b7ad-079b02290f7b
HTTP/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,用于在会话的剩余时间内对用户进行身份验证。
GET / HTTP/1.1
Host: example.com
Cookie: SESSION=4c66e474-3f5a-43ed-8e48-cc1d8cb1d1c8
SecurityContext存储库
在 Spring Security 中,用户与未来请求的关联是使用SecurityContextRepository
.
HttpSecurityContext存储库
默认实现SecurityContextRepository
是HttpSessionSecurityContextRepository
它关联了SecurityContext
到HttpSession
.
用户可以将HttpSessionSecurityContextRepository
使用另一个实现SecurityContextRepository
如果他们希望以其他方式将用户与后续请求相关联,或者根本不关联。
NullSecurityContextRepository
如果不希望将SecurityContext
设置为HttpSession
(即使用 OAuth 进行身份验证时)NullSecurityContextRepository
是SecurityContextRepository
这没有任何作用。
请求属性安全上下文存储库
这RequestAttributeSecurityContextRepository
保存SecurityContext
作为请求属性,以确保SecurityContext
可用于跨调度类型发生的单个请求,这些请求可能会清除SecurityContext
.
例如,假设客户端发出请求,经过身份验证,然后发生错误。
根据 servlet 容器实现,该错误意味着任何SecurityContext
已建立的已清除,然后进行错误分派。
进行错误分派时,没有SecurityContext
既定。
这意味着错误页面不能使用SecurityContext
用于授权或显示当前用户,除非SecurityContext
以某种方式持续存在。
-
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" />
SecurityContextPersistenceFilter
这SecurityContextPersistenceFilter
负责持久化SecurityContext
在请求之间使用SecurityContextRepository
.

在运行应用程序的其余部分之前,
SecurityContextPersistenceFilter
加载SecurityContext
从SecurityContextRepository
并将其设置为SecurityContextHolder
.
接下来,运行应用程序。
最后,如果
SecurityContext
已更改,我们保存SecurityContext
使用SecurityContextPersistenceRepository
.
这意味着当使用SecurityContextPersistenceFilter
,只需将SecurityContextHolder
将确保SecurityContext
使用SecurityContextRepository
.
在某些情况下,响应会提交并写入客户端,然后再提交SecurityContextPersistenceFilter
方法完成。
例如,如果将重定向发送到客户端,则响应会立即写回客户端。
这意味着建立HttpSession
在步骤 3 中是不可能的,因为会话 ID 无法包含在已编写的响应中。
另一种可能发生的情况是,如果客户端成功进行身份验证,则响应会在SecurityContextPersistenceFilter
完成,客户端在SecurityContextPersistenceFilter
完成第二个请求中可能存在错误的身份验证。
为避免这些问题,请SecurityContextPersistenceFilter
将HttpServletRequest
和HttpServletResponse
以检测SecurityContext
已更改,如果是,请保存SecurityContext
就在提交响应之前。
SecurityContextHolder过滤器
这SecurityContextHolderFilter
负责加载SecurityContext
在请求之间使用SecurityContextRepository
.

在运行应用程序的其余部分之前,
SecurityContextHolderFilter
加载SecurityContext
从SecurityContextRepository
并将其设置为SecurityContextHolder
.
接下来,运行应用程序。
与SecurityContextPersisteneFilter
,SecurityContextHolderFilter
仅加载SecurityContext
它不会保存SecurityContext
.
这意味着当使用SecurityContextHolderFilter
,则要求SecurityContext
被显式保存。
-
Java
-
XML
public SecurityFilterChain filterChain(HttpSecurity http) {
http
// ...
.securityContext((securityContext) -> securityContext
.requireExplicitSave(true)
);
return http.build();
}
<http security-context-explicit-save="true">
<!-- ... -->
</http>