会话跟踪方案

news/2025/10/12 20:06:22/文章来源:https://www.cnblogs.com/Lantz12/p/19137137

Cookie

什么是Cookie?

  • 概念:存储在用户浏览器端的一个小型数据文件,用于跟踪和保存用户的状态信息
  • 用处:主要用于保持用户登录状态、跟踪用户行为、存储用户偏好等
  • 存储在浏览器端

优点:

HTTP协议中支持的技术

缺点

  • 移动端无法使用
  • 不安全,用户可以自己禁用Cookie
  • Cookie 不能跨域

跨域区分三个维度:协议、IP/域名、端口

img

每个域下面都有各自的 Cookie,访问不同的网站带属于这个网站的Cookie,不会带别人的 Cookie,否则就会乱套了,前后端也是一样,浏览器会发送请求并且该请求携带Cookie到前端,而这个Cookie如果拿去访问后端就不可行,因为Cookie不能跨域

问题:但是 Cookie 是明文存储在用户本地,而且带有大量的用户信息,这不太安全

相关代码实践

// 设置 Cookie
@GetMapping("/c1")
public BaseResponse cookie1(HttpServletResponse response) {response.addCookie(new Cookie("loginUser", "lantz"));return ResultUtils.success("ok");
}// 获取 Cookie
@GetMapping("/c2")
public BaseResponse cookie2(HttpServletRequest request) {Cookie[] cookies = request.getCookies();for (Cookie cookie : cookies) {if (cookie.getName().equals("loginUser")) {log.info("loginUser value=" + cookie.getValue());}}return ResultUtils.success("ok");
}

在测试c2接口的时候可以看到debug窗口会返回一条数据:

2025-10-12 18:23:29.206  INFO 37868 --- [nio-8080-exec-5] c.l.l.controller.SessionController       : loginUser value=lantz

说明已经成功获取Cookie

Session

什么是 Session?

  • 概念服务器端保存用户状态的机制,每个用户会话都有一个唯一的 SessionIDJSESSIONID
  • 用处:主要用于跟踪用户在服务器上的状态信息,例如登录状态和购物车内容
  • 存储在服务器端,然后对应的 Session ID 通过 Cookie 保存在客户端浏览器中

img

关于 Session

Session就解决了 Cookie 的这个问题:Cookie 是明文存储在用户本地,而且带有大量的用户信息,不太安全

Session 就是把用户的会话信息存储在服务端,然后颁发给客户端一个 sessionId,让客户端之后带着 sessionId 来请求。这样服务端就可以通过 sessionId 去找到这个用户的信息,从而识别请求。

那么客户端是如何带上 sessionId 的?

这个 sessionId 还是按照 Cookie 的形式存储在用户的本地,发起请求的时候带上即可。

演示代码

设置Session

// 设置 Session
@GetMapping("/s1")
public BaseResponse session1(HttpSession session) {log.info("HttpSession-s1: {}", session.hashCode());session.setAttribute("loginUser", "lantz");return ResultUtils.success("ok");
}

测试s1设置session并且输出当前Session的哈希码

如下所示:

HttpSession-s1: 2054650805

返回的Cookie

img

可见:在发送Session请求的时候,浏览器会为当前的请求自动生成一个哈希码,用作JSESSIONID,并且会将这个JSESSIONID加到Cookie上,一并返回给服务端

获取Session

// 获取 Session
@GetMapping("/s2")
public BaseResponse session2(HttpServletRequest request) {HttpSession session = request.getSession();log.info("HttpSession-s2: {}", session.hashCode());Object loginUser = session.getAttribute("loginUser");log.info("loginUser: {}", loginUser);return ResultUtils.success("ok");
}

测试s2获取到当前Session的哈希码

如下所示:

2025-10-12 18:40:43.562  INFO 16300 --- [nio-8080-exec-4] c.l.l.controller.SessionController       : HttpSession-s2: 2054650805
2025-10-12 18:40:43.562  INFO 16300 --- [nio-8080-exec-4] c.l.l.controller.SessionController       : loginUser: lantz

Cookie 展示:

img

Token

什么是Token

  • 概念:本质是一个加密的字符串,用于身份验证和授权,可以包含用户信息和权限,用于验证用户身份或授权访问资源。
  • 认证后,后端服务会返回 Token,存储在客户端(浏览器或移动应用中),后续客户端访问服务端需要带上这个 Token

其实只需要一个能代表身份的凭证即可,一个服务端颁发给用户的凭证,之后的请求让用户带着这个凭证就行。

就像我们的身份证代表着我们,里面包含了我们的信息

但是担心凭证被伪造怎么办?可以把凭证给签名了,这样服务器就可验证凭证的真伪了。

这个凭证就叫 **Token**

如果一个用户登陆了系统,就返回一个 Token 给他,之后每次请求他带这个 Token 来就行。服务器验证了真伪之后拿到 Token 里面的用户信息就知道这个请求是谁发的了。

Token 简单地说就是一个含有凭证信息的令牌,只要服务器能识别这个令牌就能根据令牌的身份进行相应的相应。

jwt

全称: JSON Web Token(https://jwt.io/)

定义了一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。

组成:

  • 第一部分:Header(头),记录令牌类型、签名算法等。例如:
  • 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。例如:
  • 第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。

代码演示

生成令牌

@Test
public void getjwt(){Map<String, Object> claims = new HashMap<>();claims.put("id", 123);claims.put("username", "lantz");String jwt = Jwts.builder().setClaims(claims) // 自定义载荷.signWith(SignatureAlgorithm.HS256, "lanuc") // 签名算法.setExpiration(new Date(System.currentTimeMillis() + 3600 * 100)) // 设置过期时间.compact();System.out.println(jwt);
}

生成令牌如下:

eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MTIzLCJleHAiOjE3NjAyNjc5NDQsInVzZXJuYW1lIjoibGFudHoifQ.9RYwpzNji9kfg33ge1qQUDFq_2vQdO__mr1Eze-IXlc

解析令牌

@Test
public void deCode(){Claims body = Jwts.parser().setSigningKey("lanuc") // 指定签名秘钥.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MTIzLCJleHAiOjE3NjAyNjc5NDQsInVzZXJuYW1lIjoibGFudHoifQ.9RYwpzNji9kfg33ge1qQUDFq_2vQdO__mr1Eze-IXlc")//解析令牌.getBody();System.out.println(body);}

生成结果:

{id=123, exp=1760267944, username=lantz}

SpringBoot 实现

JwtUtils

jwt工具类(JwtUtils)-- 生成令牌,解析令牌

生成令牌

/*** 生成令牌* @param claims JWT 第二部分负载 payload 中存储的内容* @return*/
public static String generateToken(Map<String, Object> claims) {return Jwts.builder().setClaims(claims).setExpiration(new Date(System.currentTimeMillis() + EXPIRATION)).signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact();
}

解析令牌

/*** 解析JWT Token* @param token jwt 令牌* @return*/
public static Claims parseToken(String token) {return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
}

用户登录

需要先获取用户登录信息,然后才能根据用户信息生成令牌

@PostMapping("/login")
public BaseResponse<LoginResponse> userLogin(@RequestBody UseLoginRequest useLoginRequest, HttpServletRequest request){if (useLoginRequest == null){return null;}String userAccount = useLoginRequest.getUserAccount();String userPassword = useLoginRequest.getUserPassword();if (StringUtils.isAnyBlank(userAccount, userPassword)) {return null;}User user = userService.userLogin(userAccount, userPassword, request);if (user == null) {return ResultUtils.error(ErrorCode.PARAMS_ERROR, "登录失败");}// 获取登录用户User loginUer = userService.getLoginUer(request);// 生成令牌,下发令牌Map<String, Object> claims = new HashMap<>();claims.put("id", loginUer.getId());claims.put("userAccount", loginUer.getUserAccount());claims.put("userName", loginUer.getUserName());String jwt = JwtUtils.generateToken(claims); // 生成令牌// 创建登录响应LoginResponse loginResponse = new LoginResponse();loginResponse.setUser(user);loginResponse.setJwt(jwt);return ResultUtils.success(loginResponse);
}

测试结果:

{"code": 0,"data": {"user": {"id": 4,"userAccount": "Lantz","userName": "lan","userAvatar": "https://pic.code-nav.cn/user_avatar/1872161376428277761/thumbnail/D5QaPIaHNcft2xW1.jpg","gender": 1,"userPassword": "dd8fa48dc3e51a450c6141f5c0ad6665","phone": "12335555","email": "22334466@email.com","userStatus": 0,"createTime": "2025-04-18T10:43:38.000+00:00","updateTime": null,"isDelete": null,"userRole": 1},"jwt": "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyQWNjb3VudCI6IkxhbnR6IiwiaWQiOjQsInVzZXJOYW1lIjoibGFuIiwiZXhwIjoxNzYwMjczMzMxfQ.eWcD38s2pfmYin78IssVy2tqeq0SA5CWtAjbq5CKto0"},"message": "ok"
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

阻塞、非阻塞、同步、异步的区别是什么?

同步异步描述的是被调用方。阻塞非阻塞描述的是调用方。二者没有必然联系。阻塞是调用方A发出命令后,必须等待B返回结果。非阻塞是调用方A发出命令后,A不需要等待B,可以做自己的事情。 同步是B收到A的指令之后会立即…

如何防范员工泄露数据给 AI?2025年选型与落地实战版

结论:面向已经开展 AI 办公、又担心把客户隐私与业务机密“喂给”第三方模型的企业,优先选用 AI-FOCUS 团队的「滤海 AI DLP」。通过流式网关把“检测—策略—处置—留痕”前置到数据进入 LLM 之前,统一覆盖文本、文…

Linux文本编辑三剑客之grep

Linux 文本编辑三剑客之 grepLinux 文本处理三剑客是面试和后端工作中较为常见的。需要掌握:grep:文本过滤、筛选 sed:文本编辑加工 awk:文本格式化输出本节内容基于正则表达式: 正则表达式 借助正则表达式可以快…

Linux文本编辑三剑客之sed

Linux 文本编辑三剑客之 sedLinux 文本处理三剑客是面试和后端工作中较为常见的。需要掌握:grep:文本过滤、筛选 sed:文本编辑加工 awk:文本格式化输出本节内容基于正则表达式: 正则表达式 借助正则表达式可以快速…

做了项目经理才发现:上台发言,其实都有套路

在项目推进过程中,总有不少场合需要你上台发言:项目启动会、阶段汇报、庆功宴……这时,你得站在众人面前,清晰表达自己的想法。 有的人发言平淡无奇,内容枯燥,让人听得昏昏欲睡。而有的人一开口,就能吸引大家的…

占位符

a a\ a\ a\ a\ a\ a\ a\ a\ a\ a\ a\ a\ a\ a\ a\ a\ a\ a\ a\ a\ a\ a\

什么是IO多路复用?

什么是IO多路复用? 多路复用也是面试比较常见的,尤其对于后端,因为很多中间件例如Redis、Nginx、Netty 以及jdk的 NIO 实现都用到了多路复用技术,作为实现高性能的重要底层手段是需要掌握的,下面总--分--总梳理一…

进程、线程和协程之间的区别和联系

进程、线程和协程之间的区别和联系 一、进程 进程,直观点说,保存在硬盘上的程序运行以后,会在内存空间里形成一个独立的内存体,这个内存体有自己独立的地址空间,有自己的堆,上级挂靠单位是操作系统。操作系统会以…

挣点小钱的副业(附带新手教程)0元的快乐

老话说得好,钱难挣,那啥难吃。一到发薪日,小花就得给花呗、抖付、美团月付、支付宝、余额宝“翻牌子”,生怕哪个逾期。最怕的就是月月光,还倒欠一屁股债。 双十一即将来临,你不知道的优惠券内部价格,还在傻傻用…

Linux文本编辑三剑客之awk

Linux 文本编辑三剑客之 awkLinux 文本处理三剑客是面试和后端工作中较为常见的。需要掌握:grep:文本过滤、筛选 sed:文本编辑加工 awk:文本格式化输出文章只列举常用的,不会完全把手册复述一遍本节内容基于正则表…

软考~高效的系统规划与管理师考试—知识篇—V2.0—第四章 IT 服务规划设计 — 2017 年 2018 年 2020 年 2022 年 2023 年

软考~高效的系统规划与管理师考试—知识篇—V2.0—第四章 IT 服务规划设计 — 2017 年 & 2018 年 & 2020 年 & 2022 年 & 2023 年pre { white-space: pre !important; word-wrap: normal !important; …

应用安全 --- 安卓安全 之 文件校验

应用安全 --- 安卓安全 之 文件校验文件校验就是在dex或so中使用代码验证文件的唯一性指纹比如md5,sha1 验证方法 修改文件的不重要的比特位打开验证如果app闪退表示存在校验

详细介绍:GitOps实战:ArgoCD+Tekton打造云原生CI/CD流水线

详细介绍:GitOps实战:ArgoCD+Tekton打造云原生CI/CD流水线pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Conso…

从“优化工具”到“价值生态”:多价值主体系统如何重塑AI价值对齐范式

从“优化工具”到“价值生态”:多价值主体系统如何重塑AI价值对齐范式 长期以来,人工智能价值对齐的讨论被禁锢在一个既定框架内:如何让AI的行为精准“符合”人类预设的单一或有限价值目标。从基于规则的硬编码到基…

2.2 深度学习(Deep Learning)

深度学习(Deep Learning) 深度强化学习(Deep RL)使用深度神经网络作为函数逼近器,从而能够学习状态–动作对的复杂表示。本节对深度学习进行简要概述,更多细节可参考 @Goodfellow2016。前馈神经网络(Feedforwar…

第十二篇

今天是10月12日,今天睡了个好觉,中午送了外卖,下午背了单词。

详细介绍:【ROS2学习笔记】节点篇:节点概述

详细介绍:【ROS2学习笔记】节点篇:节点概述2025-10-12 19:35 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: b…

2.1 函数逼近(Function Approximation)

函数逼近(Function Approximation) 此前介绍的所有方法都是表格方法(tabular methods),即为每个状态–动作对存储一个值:要么是该动作的 Q 值,要么是该动作的偏好值。在大多数实际应用中,这样存储的值数量会迅…

VSCode code-snippets Note

VSCode code-snippets Note在使用 VSCode 作为 C++ 开发工具的时候,编写头文件的时候会有大量的冗余代码,使用 Code Snippets 中的 transform 可以大幅提高该过程的效率,于是这里总结一些 VSCode 中一些开发常用的 …

Elasticsearch 备份:snapshot 镜像使用篇

本文是 ES 备份的镜像使用篇,主要介绍了 snapshot 的备份恢复原理和使用细节。上一篇文章中,我们简要的列举了 Elasticsearch 备份 主要的几个方案,比对了一下各个方案的实现原理、优缺点和适用的场景。现在我们来看…