当用户第一次请求受保护的资源时,客户端HTTP请求的汇总:
1、未经认证的用户请求受保护资源
GET / HTTP/1.1
Host: example.com
Cookie: SESSION=91470ce0-3f3c-455b-b7ad-079b02290f7b
HTTP/1.1 302 Found
Location: /login
2、用户提交他们的用户名和密码
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```
3、在对用户进行认证时,会将用户关联一个新的会话id,以防止会话固定攻击
```xml
HTTP/1.1 302 Found
Location: /
Set-Cookie: SESSION=4c66e474-3f5a-43ed-8e48-cc1d8cb1d1c8; Path=/; HttpOnly; SameSite=Lax
4、后续请求包括会话cookie,该cookie用于在会话剩余时间对用户进行身份验证
GET / HTTP/1.1
Host: example.com
Cookie: SESSION=4c66e474-3f5a-43ed-8e48-cc1d8cb1d1c8
Spring Security使用SecurityContextRepository关联登录用户和登录之后发往服务器的请求
HttpSecurityContextRepository是SecurityContextRepository的默认实现,它会将SecurityContext关联到HttpSession。
不做任何关联处理
RequestAttributeSecurityContextRepository将SecurityContext设置为一个请求参数,可以保证在一个请求发生分派时还能获取到SecurityContext。比如,客户端在认证通过之后向服务器发送一个请求,但是在后续处理请求的过程中出现异常。异常出现就意味着已经建立的SecurityContext会被清除,然后分派错误请求,错误请求分派不会创建SecurityContext。这就意味着错误页面不能使用SecurityContext,除非使用某种方式持久化SecurityContext。下面是配置使用方式:
public SecurityFilterChain filterChain(HttpSecurity http) {
http
// ...
.securityContext((securityContext) -> securityContext
.securityContextRepository(new RequestAttributeSecurityContextRepository())
);
return http.build();
}
SecurityContextPersistenceFilter负责使用SecurityContextRepository处理请求之间的SecurityContext的持久化
(1)在应用程序处理后续业务之前,SecurityContextHolderFilter从SecurityContextRepository加载SecurityContext,并将其设置到SecurityContextHolder
(2)应用程序处理后续业务
(3)最后,如果SecurityContext有变动,使用SecurityContextRepository保存SecurityContext。
这就意味着当我们使用SecurityContextPersistenceFilter时,只需要配置SecurityContextHolder就能保证SecurityContext的持久化
在某些情况下,响应会在SecurityContextPersisteneFilter执行完成之前响应到客户端。例如,重定向响应会立即被响应到客户端,这就意味着步骤3中是不可能建立HttpSession的;另一种可能发生的情况是,如果客户端身份验证成功,在SecurityContextPersistenceFilter完成之前提交响应,并且客户端在SecurityContextPersistenceFilter完成之前发出第二个请求,第二个请求中可能出现错误的身份验证。
为了避免这些问题,SecurityContextPersistenceFilter封装了HttpServletRequest和HttpServletResponse来检测SecurityContext是否发生了变化,如果发生了变化,则在响应提交之前保存SecurityContext。
SecurityContextHolderFilter使用SecurityContextRepository在处理请求之间加载SecurityContext
(1)在应用程序处理后续业务之前,SecurityContextHolderFilter使用SecurityContextRepository加载SecurityContext,然后设置到SecurityContextHolder中
(2)应用程序处理后续业务
和SecurityContextPersistenceFilter不同,SecurityContextHolderFilter只加载SecurityContext,而不保存SecurityContext。这意味着当使用SecurityContextHolderFilter时,需要显式保存SecurityContext。 配置显示保存SecurityContext:
public SecurityFilterChain filterChain(HttpSecurity http) {
http
// ...
.securityContext((securityContext) -> securityContext
.requireExplicitSave(true)
);
return http.build();
}