spring-security authentication persistence

翻译版本【spring-security 6.2.1】persistence

Persisting Authentication

用户第一次请求受保护的资源时,系统会提示他们输入凭据。提示输入凭据的最常见方法之一是将用户重定向到登录页面。未经身份验证的用户请求受保护的资源的HTTP交换可能如下所示:
例1。未经认证的用户请求受保护的资源:

GET / HTTP/1.1
Host: example.com
Cookie: SESSION=91470ce0-3f3c-455b-b7ad-079b02290f7b

用户提交他们的用户名和密码。
提交用户名和密码

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

SecurityContextRepository

在Spring Security中,用户与未来请求的关联是使用SecurityContextRepository实现的。SecurityContextRepository的默认实现是DelegatingSecurityContextRepository,它委托以下内容:

  • HttpSessionSecurityContextRepository
  • RequestAttributeSecurityContextRepository

HttpSessionSecurityContextRepository

HttpSessionSecurityContextRepository将SecurityContext关联到HttpSession。如果用户希望以另一种方式将用户与后续请求关联起来,或者根本不关联,则可以用SecurityContextRepository的另一个实现替换HttpSessionSecurityContextRepository 。

NullSecurityContextRepository

如果不希望将SecurityContext与HttpSession相关联(即,当使用OAuth进行身份验证时),则NullSecurityContextRepository是SecurityContextRepository的一个实现,它什么也不做。

RequestAttributeSecurityContextRepository

RequestAttributeSecurityContextRepository将SecurityContext保存为请求属性,对于跨调度类型的单个请求可能清除SecurityContext的发生,来确保SecurityContext可用。
例如,假设客户端发出请求并通过身份验证,然后发生错误。根据servlet容器实现的不同,该错误意味着已建立的任何SecurityContext都将被清除,然后进行错误调度。当进行错误调度时,没有建立SecurityContext。这意味着错误页面不能使用SecurityContext进行授权或显示当前用户,除非SecurityContext以某种方式被持久化。

使用RequestAttributeSecurityContextRepository

public SecurityFilterChain filterChain(HttpSecurity http) {
	http
		// ...
		.securityContext((securityContext) -> securityContext
			.securityContextRepository(new RequestAttributeSecurityContextRepository())
		);
	return http.build();
}

DelegatingSecurityContextRepository

DelegatingSecurityContextRepository将SecurityContext保存到多个SecurityContextRepositorys委托,并允许按指定顺序从任何委托中检索。

下面的例子配置了最有用的安排,它允许同时使用RequestAttributeSecurityContextRepository和HttpSessionSecurityContextRepository。

配置DelegatingSecurityContextRepository

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
	http
		// ...
		.securityContext((securityContext) -> securityContext
			.securityContextRepository(new DelegatingSecurityContextRepository(
				new RequestAttributeSecurityContextRepository(),
				new HttpSessionSecurityContextRepository()
			))
		);
	return http.build();
}

注意
在SpringSecurity6中,上面显示的示例是默认配置。

SecurityContextPersistenceFilter

SecurityContextPersistenceFilter负责使用SecurityContextRepository在请求之间持久化SecurityContext。

spring-security authentication persistence_第1张图片
在这里插入图片描述
在运行应用程序的其余部分之前,SecurityContextPersistenceFilter从SecurityContextRepository加载SecurityContext,并将其设置在SecurityContextHolder上。
在这里插入图片描述
接下来,运行应用程序。
在这里插入图片描述
最后,如果SecurityContext已经更改,我们将使用SecurityContextPersistenceRepository保存SecurityContext。这意味着,当使用SecurityContextPersistenceFilter时,只需设置SecurityContextHolder就可以确保使用SecurityContextRepository持久化SecurityContext。

在某些情况下,响应在SecurityContextPersistenceFilter方法完成之前被提交并写入到客户端。例如,如果将重定向发送到客户端,则立即将响应写回客户端。这意味着在步骤3中不可能建立HttpSession,因为会话id不能包含在已经写好的响应中。另一种可能发生的情况是,如果客户端身份验证成功,则在SecurityContextPersistenceFilter完成之前提交响应,并且客户端在SecurityContextPersistenceFilter完成之前发出第二个请求,第二个请求中可能存在错误的身份验证。

为了避免这些问题,SecurityContextPersistenceFilter包装HttpServlet请求和HttpServlet响应,以检测SecurityContext是否已更改,如果已更改,则在提交响应之前保存SecurityContext。

SecurityContextHolderFilter

SecurityContextHolderFilter负责使用SecurityContextRepository在请求之间加载SecurityContext。

spring-security authentication persistence_第2张图片

在这里插入图片描述
在运行应用程序的其余部分之前,SecurityContextHolderFilter从securitycontexrepository加载SecurityContext,并将其设置在SecurityContextHolder上。

在这里插入图片描述
接下来,运行应用程序。

与SecurityContextPersistenceFilter不同,SecurityContextHolderFilter只加载SecurityContext,而不保存SecurityContext。这意味着在使用SecurityContextHolderFilter时,需要显式保存SecurityContext。

SecurityContext的显式保存

public SecurityFilterChain filterChain(HttpSecurity http) {
	http
		// ...
		.securityContext((securityContext) -> securityContext
			.requireExplicitSave(true)
		);
	return http.build();
}

在使用配置时,如果需要在请求之间持久化SecurityContext,那么使用SecurityContext设置SecurityContextHolder的任何代码也要将SecurityContext保存到SecurityContextRepository中,这一点很重要。

例如,以下代码:
使用SecurityContextPersistenceFilter设置SecurityContextHolder

SecurityContextHolder.setContext(securityContext);

应该替换为
使用SecurityContextHolderFilter设置SecurityContextHolder

SecurityContextHolder.setContext(securityContext);
securityContextRepository.saveContext(securityContext, httpServletRequest, httpServletResponse);

你可能感兴趣的:(Spring,Security,spring,spring-security)