|
此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Security 6.4.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,该 cookie 用于在会话的剩余时间内对用户进行身份验证。
GET / HTTP/1.1
Host: example.com
Cookie: SESSION=4c66e474-3f5a-43ed-8e48-cc1d8cb1d1c8
SecurityContextRepository 存储库
在 Spring Security 中,用户与未来请求的关联是使用SecurityContextRepository.
HttpSecurityContextRepository 数据库
的默认实现SecurityContextRepository是HttpSessionSecurityContextRepository它将SecurityContext到HttpSession.
用户可以将HttpSessionSecurityContextRepository使用SecurityContextRepository如果他们希望以其他方式将用户与后续请求相关联,或者根本不关联。
NullSecurityContext存储库
如果不希望将SecurityContext更改为HttpSession(即使用 OAuth 进行身份验证时)的NullSecurityContextRepository是SecurityContextRepository那什么也没做。
RequestAttributeSecurityContextRepository
这RequestAttributeSecurityContextRepository保存SecurityContext作为请求属性,以确保SecurityContext可用于跨分派类型发生的单个请求,该请求可能会清除SecurityContext.
例如,假设客户端发出请求,经过身份验证,然后发生错误。
根据 servlet 容器的实现,该错误意味着任何SecurityContext清除已建立的 ID,然后进行错误分派。
进行错误分派时,没有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" />
委托SecurityContextRepository
这DelegatingSecurityContextRepository保存SecurityContext到多个SecurityContextRepositorydelegates,并允许按指定顺序从任何代理中检索。
最有用的安排是使用以下示例进行配置,该示例允许同时使用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 中,上面显示的示例是默认配置。 |
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就在提交响应之前。
SecurityContextHolderFilter
这SecurityContextHolderFilter负责加载SecurityContext在请求之间使用SecurityContextRepository.
在运行应用程序的其余部分之前,SecurityContextHolderFilter加载SecurityContext从SecurityContextRepository并将其设置在SecurityContextHolder.
接下来,运行应用程序。
与SecurityContextPersistenceFilter,SecurityContextHolderFilter仅加载SecurityContext它不会保存SecurityContext.
这意味着,在使用SecurityContextHolderFilter,则要求SecurityContext显式保存。
-
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>
使用配置时,将SecurityContextHolder替换为SecurityContext还会保存SecurityContext到SecurityContextRepository是否应在请求之间持久保存。
例如,以下代码:
SecurityContextHolder跟SecurityContextPersistenceFilter-
Java
-
Kotlin
SecurityContextHolder.setContext(securityContext);
SecurityContextHolder.setContext(securityContext)
应替换为
SecurityContextHolder跟SecurityContextHolderFilter-
Java
-
Kotlin
SecurityContextHolder.setContext(securityContext);
securityContextRepository.saveContext(securityContext, httpServletRequest, httpServletResponse);
SecurityContextHolder.setContext(securityContext)
securityContextRepository.saveContext(securityContext, httpServletRequest, httpServletResponse)