Spring Security 6.x 系列(13)—— 会话管理及源码分析

一、会话概念

在实现会话管理之前,我们还是先来了解一下协议和会话的概念,连协议和会话都不知道是啥,还谈啥管理。

1.1 http 协议

因为我们现在的会话,基本上都是基于HTTP协议的,所以在讲解会话之前,我再带各位复习一下HTTP协议。

1.1.1 概念

HTTP:超文本传输协议(HyperText Transfer Protocol),是一种用于分布式、协作式和超媒体信息系统的应用层协议,是一种在客户端(用户)和服务器端(网站)之间进行请求和响应的规范标准(TCP),HTTP是万维网中数据通信的基础。

1.1.2 起源&发展

HTTP的发展是由蒂姆·伯纳斯-李于1989年在欧洲核子研究组织(CERN)所发起。HTTP的标准制定由万维网协会(World Wide Web Consortium,W3C)和互联网工程任务组(Internet Engineering Task Force,IETF)进行协调,最终发布了一系列的RFC。其中最著名的是1999年6月公布的 RFC 2616,定义了HTTP协议中现今广泛使用的一个版本—— HTTP 1.1

2014年12月,互联网工程任务组(IETF)的Hypertext Transfer Protocol Bishttpbis)工作小组将HTTP/2标准提议递交至IESG进行讨论,于2015年2月17日被批准。HTTP/2标准于2015年5月以RFC 7540正式发表,取代HTTP 1.1成为HTTP的实现标准

1.1.3 特点

  • 基于 请求-响应 模式:

    HTTP协议规定:请求是从客户端发出的,最后由服务器端接受并响应该请求。

  • 无状态保存:

    HTTP是一种不保存用户状态,即无状态(stateless)的协议。HTTP协议自身不对请求和响应之间的通信状态进行保存,也就是说在HTTP这个级别,协议对于发送过的请求或响应都不做持久化处理。

    HTTP协议的无状态,指的是每当有新的请求发送时,就会有对应的响应产生,HTTP协议本身并不保留之前一切的请求或响应的报文信息。这是为了更快地处理大量事务,确保协议的可伸缩性,而特意把HTTP协议设计成如此简单的。可随着Web的不断发展,因无状态而导致业务处理变得棘手的情况也增多了。比如:用户登录到一家购物网站,然后他跳转到该站的其他页面,也需要能继续保持登录状态。针对这个实例,网站为了能够掌握是谁发送的请求,需要保存用户的状态。HTTP/1.1虽然是无状态的协议,但为了实现期望的保持状态的功能,于是就引入了CookieSession技术。有了CookieSession,再用HTTP协议通信,就可以管理状态了。

  • 无连接:

    无连接的含义就是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间,并可以提高并发性能,不用和每个用户建立长久的连接,请求一次响应一次,服务端和客户端就中断了。

1.2 会话概念

会话(Session):在计算机中,尤其是在网络应用中,称为会话控制,它是以无状态的HTTP协议来维持用户状态的一种解决方案。

我们知道HTTP是无状态的协议,这意味着每次客户端检索网页时,都要单独打开一个服务器连接,因此服务器不会存储先前客户端请求的任何信息。

HTTP 本身的无状态使得用户在与服务器的交互过程中,每个请求之间都没有关联性。这意味着用户的访问没有身份记录,站点也无法为用户提供个性化的服务,而Session的诞生解决了这个难题。服务器通过与用户约定,发起每个请求时都要携带一个id类的信息,从而让不同请求之间有了关联,而id又可以很方便地绑定具体用户,所以我们可以把不同请求归类到同一用户。基于这个方案,为了让用户每个请求都携带同一个id,在不妨碍体验的情况下,cookie是很好的载体。当用户首次访问系统时,系统会为该用户生成一个sessionid,并添加到cookie中。在该用户的会话期内,每个请求都自动携带该cookie,因此系统可以很轻易地识别出这是来自哪个用户的请求。

jsessionid就是客户端用来保存sessionid的变量,主要是针对j2ee实现的web容器。

尽管 cookie 非常有用,但有时用户会在浏览器中禁用它,这么做可能是出于安全考虑,也可能是为了保护个人隐私。

在这种情况下,基于cookie实现的 sessionld 自然就无法正常使用了。因此,有些服务还支持用 URL重写 的方式来实现类似的体验,例如:http://www.baidu.com;jessionid=xxx URL重写原本是为了兼容禁用 cookie 的浏览器而设计的,但也容易被黑客利用。黑客只需访问一次系统,将系统生成的sessionld提取并拼凑在URL上,然后将该URL发给一些取得信任的用户。只要用户在session有效期内通过此URL进行登录,该sessionld就会绑定到用户的身份,黑客便可以轻松享有同样的会话状态,完全不需要用户名和密码,这就是典型的会话固定攻击。

我们只需在两个浏览器中用同一个账号登录就会发现,默认情况下,我们的系统并未有任何会话并发的限制,也就是一个账户能在多处同时登录,这并不是一个好的策略。而Spring Security已经为我们提供了完善的会话管理功能,包括:会话固定攻击会话超时检测以及会话并发控制等。

1.3 HttpSession

HttpSession 是一个服务端的概念,服务端生成的 HttpSession 都会有一个对应的 sessionid,这个 sessionid 会通过 cookie 传递给前端,前端以后每次发送请求的时候,都会带上这个 sessionid 参数。服务端看到这个 sessionid 就会把这个前端请求和服务端的某一个 HttpSession 对象对应起来,形成会话的感觉。

浏览器关闭并不会导致服务端的 HttpSession 失效,想让服务端的 HttpSession 失效,要么手动调用 HttpSession#invalidate()方法,要么等到 session 自动过期,要么重启服务端。

但是为什么有的人会感觉浏览器关闭之后 session 就失效了呢?这是因为浏览器关闭之后,保存在浏览器里边的 sessionid 就丢了(默认情况下)。所以当浏览器再次访问服务端的时候,服务端会给浏览器重新分配一个 sessionid,这个 sessionid 和之前的 HttpSession 对应不上,所以用户就会感觉 session 失效。

但是我们也可以通过手动配置,让浏览器重启之后 sessionid 不丢失,但是这样会带来安全隐患,所以一般不建议。

Spring Boot 为例,服务端生成 sessionid 之后,返回给前端的响应头是这样的:

在这里插入图片描述

在服务端的响应头中有一个 Set-Cookie 字段,该字段指示浏览器更新 sessionid,同时大家注意还有一个 HttpOnly 属性,这个表示通过 JS 脚本无法读取到 Cookie 信息,这样能有效的防止 XSS 攻击。

下一次在浏览器中发送对某个接口的请求时候,就会自觉的携带上这个 sessionid 了:

在这里插入图片描述

二、会话配置

2.1 创建策略

Spring Security 中的 SessionCreationPolicy 枚举类,声明了会话的创建策略:

public enum SessionCreationPolicy {

	/**
	 * Always create an {@link HttpSession}
	 */
	ALWAYS,

	/**
	 * Spring Security will never create an {@link HttpSession}, but will use the
	 * {@link HttpSession} if it already exists
	 */
	NEVER,

	/**
	 * Spring Security will only create an {@link HttpSession} if required
	 */
	IF_REQUIRED,

	/**
	 * Spring Security will never create an {@link HttpSession} and it will never use it
	 * to obtain the {@link SecurityContext}
	 */
	STATELESS

}

通过以下选项准确控制会话合适创建及 Spring Security 合适与之交互:

策略名称描述
ALWAYS如果没有存 Session 就创建一个
NEVER不会创建 Session ,但是如果应用中其他地方创了,那么 Spring Security 将会使用它
IF_REQUIRED如果需要就创建一个 Session(默认)
STATELESS绝对不会创建 Session ,也不使用 Session ,每个请求都需要重新进行身份验证

通过以下方式对改策略进行配置:

// 会话创建策略
http.sessionManagement(session -> session
        .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
        );

默认情况下, Spring Security 会为每个登录成功的用户创建一个 Session 也就是使用 IF_REQUIRED 策略。

2.2 检测超时

2.2.1 超时时间

可以在 Sevlet 容器中设置 Session 的有效期,如下设置有效期为3600秒(默认):

server:
  servlet:
    session:
      timeout: 3600s

2.2.2 失效跳转路径

会话超时之后,可以通过Spring Security 设置失效跳转路径:

http.sessionManagement(session -> session
                .invalidSessionUrl("/login?error=INVALID_SESSION") //  失效跳转路径
                .sessionCreationPolicy(SessionCreationPolicy.ALWAYS) // 创建策略
        );

如果用户注销没有关闭浏览器,浏览器中的 cookie 不会被清除,注销登录时可以明确地删除名称为JSESSIONIDcookie

http.logout(logout -> logout
        .deleteCookies("JSESSIONID")
    );

注意:
这不能保证适用于每个 servlet 容器,因此您需要在您的环境中对其进行测试。

下面的方法与容器无关,并且适用于任何支持标头的容器:

HeaderWriterLogoutHandler clearSiteData = new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(ClearSiteDataHeaderWriter.Directive.ALL));
http.logout(logout -> logout.addLogoutHandler(clearSiteData));

2.3 无效会话策略

通过定义 CustomInvalidSessionStrategy 实现 InvalidSessionStrategy 接口,配置无效会话策略:

http
    .sessionManagement(session -> session
        .invalidSessionStrategy(new CustomInvalidSessionStrategy())
    );

2.4 会话失效策略

在前后端分离时,会话失效不会虚后端跳转页面,可以设置返回JSON数据:

.sessionConcurrency(sessionConcurrency -> sessionConcurrency.expiredSessionStrategy(event -> {
            HttpServletResponse response = event.getResponse();
            response.setContentType("application/json;charset=utf-8"); // 返回JSON
            response.setStatus(HttpStatus.BAD_REQUEST.value());  // 状态码
            Map<String, Object> result = new HashMap<>(); // 返回结果
            result.put("msg", "当前会话已失效");
            result.put("code", 401);
            response.getWriter().write(JSONUtil.toJsonStr(result));
        })
)

注意:expiredSessionStrategyConcurrencyControlConfigurer中的方法。

2.5 并发控制

并发控制可以限制在当前系统中,同一个用户可以同时创建的会话数量。一般用于踢人下线,当同一用户登录后,在另一个地方重新登录,会让之前登录的用户直接退出,提示您的账号已经在其他地方登录。默认配置是没有限制的。

首先添加一个监听器,监听会话声明周期事件:

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

配置 maximumSessions 限制用户最大会话数为 1第二次登录会导致第一次登录失效

配置 maxSessionsPreventsLogin 如果为 true ,已登录时,阻止其他登录。

// 会话策略
 http.sessionManagement(session -> session
                 .maximumSessions(1)  // 用户最大会话数为 1,后面的登陆就会自动踢掉前面的登陆
                 .maxSessionsPreventsLogin(true); // 已登录时,阻止其他登录
         );

在一个浏览器登录成功后切换到另一个浏览器再次登录时,提示最大会话数超出限制:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/287320.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Nginx(十三) 配置文件详解 - 反向代理(超详细)

本篇文章主要讲ngx_http_proxy_module和ngx_stream_proxy_module模块下各指令的使用方法。 1. 代理请求 proxy_pass 1.1 proxy_pass 代理请求 Syntax: proxy_pass URL; Default: — Context: location, if in location, limit_except 设置代理服务器的协议和地址以…

【模拟电路】模拟集成电路之神-NE555

一、集成电路NE555简介 二、功能框图与引脚说明 三、比较器&#xff08;运放&#xff09; 四、反相门&#xff08;非门&#xff09; 五、或非门 六、双稳态触发器 七、NE555的工作原理 集成电路NE555的芯片手册 C5157696 一、集成电路NE555简介 NE555起源于上个世纪70年代&a…

element-ui Tree 树形控件 过滤保留子级并获取过滤后的数据

本示例基于vue2 element-ui element-ui 的官网demo是只保留到过滤值一级的&#xff0c;并不会保留其子级 目标 1、Tree 树形控件 保留过滤值的子级 2、在第一次过滤数据的基础上进行第二次过滤 先看效果 Tree 树形控件 保留过滤值的子级 <el-treeclass"filter-t…

宝藏推荐:其实,这些工具一点不输Intercom-

在当今快节奏的商业环境中&#xff0c;提供优质的客户服务和支持是每个企业都追求的目标。为了实现这一目标&#xff0c;许多企业都在寻找可以帮助他们提供高效和个性化客户支持的工具。Intercom是一个非常受欢迎的客户支持工具&#xff0c;但它并不是唯一的选择。在本文中&…

玩转贝启科技BQ3588C开源鸿蒙系统开发板 —— 编译构建及此过程中的踩坑填坑(1)

接前一篇文章&#xff1a;玩转贝启科技BQ3588C开源鸿蒙系统开发板 —— 代码下载&#xff08;2&#xff09; 本文主要参考&#xff1a; BQ3588C_代码下载 上一回完成了代码下载&#xff0c;本回开始进行编译构建。 1. 编译构建 &#xff08;1&#xff09;执行prebuilts 在源…

用 MATLAB 产生单位抽样序列、单位阶跃序列、矩形序列、正弦序列和复指数序列

%% 单位抽样&#xff08;脉冲&#xff09;序列&#xff08;冲激函数&#xff09; % 参数设置 n -10:10; % 定义时间范围 delta (n 0); % 生成单位抽样序列% 绘图 figure; stem(n, delta); title(单位抽样序列); xlabel(n); ylabel(delta[n]);%% 单位阶跃序列 % 参数设置 n …

LanChatRoom局域网聊天室

CPP已经结课&#xff0c;我提交的项目是Qt的入门项目&#xff0c;局域网聊天室LanChatRoom。 这个代码重构了很多遍。第一遍是照着明哥推荐到书&#xff0c;把代码抄了一遍。 但抄下来之后&#xff0c;各种问题&#xff0c;而且是清朝老代码。抄了一遍之后&#xff0c;对代码的…

深度学习 Day23——J3DenseNet算法实战与解析

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制&#x1f680; 文章来源&#xff1a;K同学的学习圈子 文章目录 前言1 我的环境2 pytorch实现DenseNet算法2.1 前期准备2.1.1 引入库2.1.2 设…

JavaScript中alert、prompt 和 confirm区别及使用【通俗易懂】

✨前言✨   本篇文章主要在于&#xff0c;让我们看几个与用户交互的函数&#xff1a;alert&#xff0c;prompt 和confirm的使用及区别 &#x1f352;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f352;博主将持续更新学习记录收获&…

HarmonyOS页面和自定义组件生命周期

页面和自定义组件生命周期 在开始之前&#xff0c;我们先明确自定义组件和页面的关系&#xff1a; 自定义组件&#xff1a;Component装饰的UI单元&#xff0c;可以组合多个系统组件实现UI的复用。页面&#xff1a;即应用的UI页面。可以由一个或者多个自定义组件组成&#xff…

【算法每日一练]-数论 (保姆级教程 篇2 )#行列式 #甜甜花研究 #约数个数 #模数 #数树 #盒子与球

目录 今日知识点&#xff1a; 辗转相减法化下三角求行列式 组合数动态规划打表 约数个数等于质因数的次方1的乘积 求一个模数 将n个不同的球放入r个不同的盒子&#xff1a;f[i][j]f[i-1][j-1]f[i-1][j]*j 行列式 甜甜花的研究 约数个数 模数 数树 盒子与球 行列…

LinkedList与ArrayList的比较

1.LinkedList 基于双向链表&#xff0c;无需连续内存 随机访问慢&#xff08;要沿着链表遍历&#xff09; 头尾插入删除性能高 占用内存多 2.ArrayList 基于数组&#xff0c;需要连续内存 随机访问快&#xff08;指根据下标访问&#xff09; 尾部插入、删除性能可以&…

西门子宣布SIMATIC S-300停产?找找理想替代品——钡铼BL30x系列工控机

1994年&#xff0c;西门子发布了S7系列的第一批产品&#xff0c;其中包括S7-300。SIMATIC S7的推出也见证了新的现场总线标准Profibus的发布&#xff0c;以及率先使用工业总线来促进自动化设备之间的通信。S7-300 CPU系列的巨大成功也帮助西门子进一步巩固了其全球自动化技术领…

格局初现:京东阿里都瞄准了这个万亿级的大市场

核 心 要 点 ▪ 企业采购有哪些痛点和解决方案&#xff1f;行业的关键赛点是什么&#xff1f; ▪ 现行格局是何情况&#xff1f;代表性玩家各自有何特点&#xff1f; ▪ 未来企业采购将往何处去&#xff1f; 当这样一组数据摆在眼前的时候&#xff0c;你或许会感到难以置…

Gitee

Gitee码云 0. 笔记说明1. Gitee概述2. Gitee和GitHub3. 创建Git远程仓库4. 分享已有项目到Gitee5. 文件恢复和合并6. 文件push或pull冲突7. 添加项目成员 0. 笔记说明 该笔记以IDEA 2023专业版进行操作需提前注册好个人gitee账号安装好IDEA的相关gitee插件或者安装Git Bash软件…

C语言:二分查找查找有序数组中的元素

前言 在我们学习C语言的过程中&#xff0c;如果要查找一个数组当中是否存在某一个元素&#xff0c;我们可能会遍历整个数组&#xff0c;来依次判断是否存在这个函数&#xff0c;但这么做是效率极低的&#xff0c;如果数组中有很多个元素&#xff0c;那么我们要查找半天 二分查…

【CASS精品教程】CASS11计算城镇建筑密度

CASS中可以很方便计算建筑密度。 文章目录 一、建筑密度介绍二、CASS计算建筑密度1. 绘制宗地范围2. 绘制建筑物3. 计算建筑密度三、注意事项一、建筑密度介绍 建筑密度(building density;building coverage ratio),指在一定范围内,建筑物的基底面积总和与占用地面积的比…

CTFshow web入门web128-php特性31

开启环境: 一个新的姿势&#xff0c;当php扩展目录下有php_gettext.dll时&#xff1a; _()是一个函数。 _()gettext() 是gettext()的拓展函数&#xff0c;开启text扩展get_defined_vars — 返回由所有已定义变量所组成的数组。 call_user_func — 把第一个参数作为回调函数调…

JAVAEE初阶相关内容第二十弹--HTTP协议

写在前&#xff1a;2024年啦&#xff01;新的一年要努力学习啦 本篇博客围绕HTTP协议&#xff0c;对HTTP协议进行了解&#xff0c;需要理解其工作过程&#xff0c;对HTTP协议格式要清楚&#xff0c;通过抓包工具进行协议分析&#xff0c;认识“方法”、“请求报头”&#xff0c…

阿里云迁移AWS视频点播技术攻坚

文章目录 &#x1f437; 背景&#x1f9a5; 简述&#x1f425; Aws服务&#x1f99c; AWS CloudFormation&#x1f41e; 问题&#x1f409; 落地方案&#x1f989; Aws vs Aliyun&#x1f344; 避坑指南 &#x1f437; 背景 由于AWS整体成本略低于阿里云&#xff0c;公司决定将…