javawebの会话跟踪方案
Cookie
什么是Cookie?
-
概念:存储在用户浏览器端的一个小型数据文件,用于跟踪和保存用户的状态信息
-
用处:主要用于保持用户登录状态、跟踪用户行为、存储用户偏好等
-
存储在浏览器端
优点:
HTTP协议中支持的技术
缺点:
-
移动端无法使用
-
不安全,用户可以自己禁用
Cookie -
Cookie 不能跨域
跨域区分三个维度:协议、IP/域名、端口
关于 Cookie

每个域下面都有各自的 Cookie,访问不同的网站带属于这个网站的Cookie,不会带别人的 Cookie,否则就会乱套了,前后端也是一样,浏览器会发送请求并且该请求携带Cookie到前端,而这个Cookie如果拿去访问后端就不可行,因为Cookie不能跨域
问题:但是 Cookie 是明文存储在用户本地,而且带有大量的用户信息,这不太安全
相关代码实践
▼java复制代码// 设置 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窗口会返回一条数据:
▼java复制代码2025-10-12 18:23:29.206 INFO 37868 --- [nio-8080-exec-5] c.l.l.controller.SessionController : loginUser value=lantz
说明已经成功获取Cookie了
Session
什么是 Session?
-
概念:服务器端保存用户状态的机制,每个用户会话都有一个唯一的
SessionID(JSESSIONID) -
用处:主要用于跟踪用户在服务器上的状态信息,例如登录状态和购物车内容
-
存储在服务器端,然后对应的 Session ID 通过 Cookie 保存在客户端浏览器中

关于 Session
Session就解决了 Cookie 的这个问题:Cookie 是明文存储在用户本地,而且带有大量的用户信息,不太安全
Session 就是把用户的会话信息存储在服务端,然后颁发给客户端一个 sessionId,让客户端之后带着 sessionId 来请求。这样服务端就可以通过 sessionId 去找到这个用户的信息,从而识别请求。
那么客户端是如何带上 sessionId 的?
这个 sessionId 还是按照 Cookie 的形式存储在用户的本地,发起请求的时候带上即可。
演示代码
设置Session
▼java复制代码// 设置 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的哈希码
如下所示:
▼text复制代码HttpSession-s1: 2054650805
返回的Cookie

可见:在发送Session请求的时候,浏览器会为当前的请求自动生成一个哈希码,用作JSESSIONID,并且会将这个JSESSIONID加到Cookie上,一并返回给服务端
获取Session
▼java复制代码// 获取 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的哈希码
如下所示:
▼bash复制代码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 展示:

Token
什么是Token?
-
概念:本质是一个加密的字符串,用于身份验证和授权,可以包含用户信息和权限,用于验证用户身份或授权访问资源。
-
认证后,后端服务会返回 Token,存储在客户端(浏览器或移动应用中),后续客户端访问服务端需要带上这个 Token
其实只需要一个能代表身份的凭证即可,一个服务端颁发给用户的凭证,之后的请求让用户带着这个凭证就行。
就像我们的身份证代表着我们,里面包含了我们的信息
但是担心凭证被伪造怎么办?可以把凭证给签名了,这样服务器就可验证凭证的真伪了。
这个凭证就叫 **Token**
如果一个用户登陆了系统,就返回一个 Token 给他,之后每次请求他带这个 Token 来就行。服务器验证了真伪之后拿到 Token 里面的用户信息就知道这个请求是谁发的了。
Token 简单地说就是一个含有凭证信息的令牌,只要服务器能识别这个令牌就能根据令牌的身份进行相应的相应。
jwt
全称: JSON Web Token(https://jwt.io/)
定义了一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。
组成:
-
第一部分:Header(头),记录令牌类型、签名算法等。例如:{"alg":"HS256","type":"JWT"}
-
第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。例如:{"id":"1","username":"Tom"}
-
第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。
代码演示
生成令牌
▼java复制代码@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); }
生成令牌如下:
▼text复制代码eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MTIzLCJleHAiOjE3NjAyNjc5NDQsInVzZXJuYW1lIjoibGFudHoifQ.9RYwpzNji9kfg33ge1qQUDFq_2vQdO__mr1Eze-IXlc
解析令牌
▼java复制代码@Test public void deCode(){ Claims body = Jwts.parser() .setSigningKey("lanuc") // 指定签名秘钥 .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MTIzLCJleHAiOjE3NjAyNjc5NDQsInVzZXJuYW1lIjoibGFudHoifQ.9RYwpzNji9kfg33ge1qQUDFq_2vQdO__mr1Eze-IXlc")//解析令牌 .getBody(); System.out.println(body); }
生成结果:
▼json复制代码{id=123, exp=1760267944, username=lantz}
SpringBoot 实现
JwtUtils
jwt工具类(JwtUtils)-- 生成令牌,解析令牌
生成令牌
▼java复制代码/** * 生成令牌 * @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(); }
解析令牌
▼java复制代码/** * 解析JWT Token * @param token jwt 令牌 * @return */ public static Claims parseToken(String token) { return Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(token) .getBody(); }
用户登录
需要先获取用户登录信息,然后才能根据用户信息生成令牌
▼java复制代码@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); }
测试结果:
▼json复制代码{ "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" }
