SpringSecurity系列——持久认证(Persisting Authentication),会话管理day3-2(源于官网5.7.2版本)

181 篇文章 3 订阅
24 篇文章 31 订阅

前言

源于官方最新5.7.2文档,若你觉得官方文档阅读起来很枯燥,内容复杂,我提供了解析概括在每个部分的结尾,我对官方文档的内容做了一些改变,实例代码我会在后续进行更新,请查看如:SpringSecurity系列——认证架构实例代码的文章

但是如果你有能力,还是推荐直接阅读官方文档

持久认证(Persisting Authentication)

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

这里的302表示重定向

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
//经过身份验证的用户与新会话相关联
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(Http安全上下文存储库)

SecurityContextRepository 的默认实现是 HttpSessionSecurityContextRepository,它将 SecurityContext 与 HttpSession 相关联。 如果用户希望以其他方式将用户与后续请求关联或根本不关联,则用户可以将 HttpSessionSecurityContextRepository 替换为 SecurityContextRepository 的另一个实现。

NullSecurityContextRepository(空安全上下文存储库)

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

RequestAttributeSecurityContextRepository(请求属性安全上下文存储库)

RequestAttributeSecurityContextRepository 将 SecurityContext 保存为请求属性,以确保 SecurityContext 可用于跨越可能清除 SecurityContext 的调度类型发生的单个请求。

例如,假设客户端发出请求,经过身份验证,然后发生错误。 根据 servlet 容器实现,错误意味着已建立的任何 SecurityContext 都被清除,然后进行错误分派。 进行错误分派时,没有建立 SecurityContext。 这意味着错误页面不能使用 SecurityContext 进行授权或显示当前用户,除非 SecurityContext 以某种方式持久化。
示例 5. 使用 RequestAttributeSecurityContextRepository

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

SecurityContextPersistenceFilter(安全上下文持久化过滤器)

SecurityContextPersistenceFilter 负责使用 SecurityContextRepository 在请求之间持久化 SecurityContext。
在这里插入图片描述

  1. 在运行应用程序的其余部分之前,SecurityContextPersistenceFilter 从 SecurityContextRepository 加载 SecurityContext 并将其设置在 SecurityContextHolder 上。
  2. 接下来,运行应用程序。
  3. 最后,如果 SecurityContext 已更改,我们使用 SecurityContextPersistenceRepository 保存 SecurityContext。 这意味着在使用 SecurityContextPersistenceFilter 时,只需设置 SecurityContextHolder 即可确保使用 SecurityContextRepository 持久化 SecurityContext。

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

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

SecurityContextHolderFilter(安全上下文持有者过滤器)

SecurityContextHolderFilter 负责使用 SecurityContextRepository 在请求之间加载 SecurityContext。
在这里插入图片描述

  1. 在运行应用程序的其余部分之前,SecurityContextHolderFilter 从 SecurityContextRepository 加载 SecurityContext 并将其设置在 SecurityContextHolder 上。
  2. 接下来,运行应用程序。

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

显式保存 SecurityContext

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

解释概括

  1. 用户第一次请求受保护资源时会触发重定向至认证登录的界面
  2. SecurityContextRepository 的默认实现是 HttpSecurityContextRepository,将 SecurityContext 与 HttpSession 相关联,若不想实现可以使用NullSecurityContextRepository
  3. RequestAttributeSecurityContextRepository将 SecurityContext 保存为请求属性,使用SecurityContextPersistenceFilter 负责使用 SecurityContextRepository 在请求之间持久化 SecurityContext,以确保 SecurityContext 可用于跨越可能清除 SecurityContext 的调度类型发生的单个请求
  4. 使用 SecurityContextPersistenceFilter 时,只需设置 SecurityContextHolder 即可确保使用 SecurityContextRepository 持久化 SecurityContext
  5. SecurityContextHolderFilter 只加载 SecurityContext 而不会保存 SecurityContext,所以需要我们自己进行显式保存

Session Management(会话管理)

Force Eager Session Creation(强制急切会话创建)

有时,急切地创建会话可能很有价值。 这可以通过使用可以使用配置的 ForceEagerSessionCreationFilter 来完成

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
    http
        .sessionManagement(session -> session
            .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
        );
    return http.build();
}

Detecting Timeouts(检测超时)

您可以配置 Spring Security 以检测无效会话 ID 的提交并将用户重定向到适当的 URL。 这是通过会话管理元素实现的:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
    http
        .sessionManagement(session -> session
            .invalidSessionUrl("/invalidSession.htm")
        );
    return http.build();
}

请注意,如果您使用此机制来检测会话超时,如果用户注销然后重新登录而不关闭浏览器,它可能会错误地报告错误。 这是因为当您使会话无效时会话 cookie 不会被清除,即使用户已注销也会重新提交。 您可以在注销时显式删除 JSESSIONID cookie,例如在注销处理程序中使用以下语法:
但这不能保证适用于每个 servlet 容器

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
    http
        .logout(logout -> logout
            .deleteCookies("JSESSIONID")
        );
    return http.build();
}

Concurrent Session Control(并发会话控制)

如果您希望限制单个用户登录到您的应用程序的能力,Spring Security 通过以下简单的补充支持开箱即用。 首先,您需要将以下侦听器添加到您的配置中,以使 Spring Security 更新有关会话生命周期事件

@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
    return new HttpSessionEventPublisher();
}

然后添加以下内容

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
    http
        .sessionManagement(session -> session
            .maximumSessions(1)
        );
    return http.build();
}

这将阻止用户多次登录 - 第二次登录将导致第一次登录无效。 通常您希望阻止第二次登录,在这种情况下您可以使用

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
    http
        .sessionManagement(session -> session
            .maximumSessions(1)
            .maxSessionsPreventsLogin(true)
        );
    return http.build();
}

第二次登录将被拒绝。 “拒绝”是指如果使用基于表单的登录,用户将被发送到 authentication-failure-url。 如果通过另一种非交互机制进行第二次身份验证,例如“remember-me”,则会向客户端发送“unauthorized”(401)错误。 如果您想使用错误页面,则可以将属性 session-authentication-error-url 添加到 session-management 元素。

如果您为基于表单的登录使用定制的身份验证过滤器,则必须显式配置并发会话控制支持。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 `kubectl` 命令行工具中,你可以使用 `--help` 参数来查看命令的帮助文档,包括 YAML 文件的格式要求和示例。例如,使用 `kubectl create --help` 命令可以查看如下内容: ``` Create a resource from a file or from stdin. JSON and YAML formats are accepted. Usage: kubectl create (-f FILENAME | --filename=FILENAME) [options] kubectl create (-k DIRECTORY | --kustomize=DIRECTORY) [options] kubectl create clusterrolebinding NAME --clusterrole=ROLE [--user=USER] kubectl create clusterrole NAME --verb=verb --resource=resource.group [--resource-name=resource.name] kubectl create configmap NAME [--from-literal=key1=value1] [--from-literal=key2=value2] [--from-file=[key=]source] [--dry-run=server|client|none] [--output=wide|yaml|json] [options] kubectl create cronjob NAME --image=image [--schedule=''] --command -- [COMMAND] [args...] [options] kubectl create deployment NAME --image=image [--dry-run=server|client|none] [--output=wide|yaml|json] [options] kubectl create job NAME --image=image --command -- [COMMAND] [args...] [options] kubectl create namespace NAME [--dry-run=server|client|none] [--output=wide|yaml|json] [options] kubectl create secret generic NAME [--from-literal=key1=value1] [--from-literal=key2=value2] [--from-file=[key=]source] [--dry-run=server|client|none] [--output=wide|yaml|json] [options] kubectl create service NAME --tcp=port1,port2,... [--dry-run=server|client|none] [--output=wide|yaml|json] [options] kubectl create serviceaccount NAME [--dry-run=server|client|none] [--output=wide|yaml|json] [options] Examples: # Create a pod using the data in pod.json. kubectl create -f ./pod.json # Create a pod based on the JSON passed into stdin. cat pod.json | kubectl create -f - # Edit the data in EDITOR (default vim). kubectl create configmap my-config --from-file=config.json --edit # Create a new namespace named my-namespace kubectl create namespace my-namespace Options: -f, --filename='': Filename, directory, or URL to files to use to create the resource -k, --kustomize='': Process a kustomization directory. This flag can't be used together with -f or -R. --edit=false: Edit the data in $EDITOR --force=false: Create resource even if it already exists --dry-run='none': Must be "none", "server", or "client". If client strategy, only print the object that would be sent, without sending it. If server strategy, submit server-side request without persisting the resource. -o, --output='': Output format. One of: yaml, json, wide, name, go-template-file, go-template, jsonpath-file, jsonpath. If unspecified, will default to yaml for standalone objects and table for lists. --record=false: Record current kubectl command in the resource annotation. If set to false, do not record the command. If set to true, record the command. If not set, default to updating the existing annotation value only if one already exists. ``` 在这个帮助文档中,你可以看到 `kubectl create` 命令支持不同类型的资源对象,包括 Pod、Deployment、Service、Secret 等。对于每个资源对象类型,文档都提供了示例和参数说明。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值