cookie、token、session理解

一、为什么 JSESSIONID 会在 Cookie 中?

核心原因:HTTP 是无状态协议

┌─────────────────────────────────────────────────────────────────────┐
│ HTTP 无状态问题 │
│ │
│ 请求1: 用户登录 → 服务器验证通过 │
│ 请求2: 用户访问页面 → 服务器不知道这是同一个用户 ❌ │
│ │
│ 解决方案:需要某种机制来"记住"用户 │
└─────────────────────────────────────────────────────────────────────┘

JSESSIONID 的传递机制

┌─────────────────────────────────────────────────────────────────────┐
│ JSESSIONID 工作流程 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 浏览器 │ │ 服务器 │ │ Session │ │
│ │ │ │ │ │ 存储区 │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ │ 1. 首次请求 │ │ │
│ │ (无 Cookie) │ │ │
│ │ ──────────────────>│ │ │
│ │ │ 2. 创建 Session │ │
│ │ │ 生成 JSESSIONID │ │
│ │ │ ──────────────────>│ 存储用户数据 │
│ │ │ │ │
│ │ 3. 响应 + Set-Cookie │ │
│ │ JSESSIONID=ABC123 │ │ │
│ │ │ 6. 查找 Session │ │
│ │ │ 根据 JSESSIONID │ │
│ │ │ ──────────────────>│ 获取用户数据 │
│ │ │ │ │
│ │ 7. 返回数据 │ │ │
│ │ ❌ 有大小限制(4KB)

URL 重写 ;jsessionid=ABC123 拼接到 URL ✅ Cookie 禁用时可用❌ 不安全、易泄露

表单隐藏字段 ✅ 可控❌ 每个表单都要添加

Spring Boot 默认配置:
// SessionCookieConfig 默认配置
server.servlet.session.cookie:
name: JSESSIONID # Cookie 名称
http-only: true # 防止 JS 访问
secure: false # 仅 HTTPS 传输(生产环境应开启)
same-site: lax # CSRF 防护
max-age: -1 # 会话级别(浏览器关闭即失效)

二、Cookie、Session、Token 三者关系

关系图解

┌─────────────────────────────────────────────────────────────────────┐
│ 三者关系全景图 │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 客户端 (浏览器/APP) │ │
│ │ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Cookie │ │ Token │ │ │
│ │ │ (存储容器) │ │ (存储容器) │ │ │
│ │ │ │ │ │ │ │
│ │ │ • JSESSIONID │ │ • JWT 字符串 │ │ │
│ │ │ • 其他数据 │ │ • 可存 LocalStorage │ │
│ │ └──────┬───────┘ └──────┬───────┘ │ │
│ └─────────┼────────────────────────┼─────────────────────────┘ │
│ │ │ │
│ │ HTTP 请求携带 │ HTTP 请求携带 │
│ │ Cookie: JSESSIONID=... │ Authorization: Bearer ... │
│ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 服务器端 │ │
│ │ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Session │ │ Token │ │ │
│ │ │ (数据存储) │ │ (自包含数据) │ │ │
│ │ │ │ │ │ │ │
│ │ │ • 用户信息 │ │ • 用户信息 │ │ │
│ │ │ • 会话状态 │ │ • 过期时间 │ │ │
│ │ │ • 服务器内存 │ │ • 签名验证 │ │ │
│ │ │ /Redis/DB │ │ • 无需服务器存储│ │ │
│ │ └──────────────┘ └──────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ 💡 关键区别: │
│ • Cookie 是存储容器,Session 是服务器数据 │
│ • JSESSIONID 是 Session 的"钥匙",存放在 Cookie 中 │
│ • Token 是自包含的,不需要服务器存储会话数据 │
└─────────────────────────────────────────────────────────────────────┘

三者本质区别

┌─────────────────────────────────────────────────────────────────────┐
│ 本质对比 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ Cookie │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 📦 存储容器(客户端) │ │
│ │ • 可以存储 Session ID、Token、或其他数据 │ │
│ │ • 浏览器自动管理,每次请求自动携带 │ │
│ │ • 大小限制 4KB,有数量限制 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ Session │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 🗄️ 服务器端数据存储 │ │
│ │ • 需要 Session ID 来查找(通常通过 Cookie 传递) │ │
│ │ • 数据存储在服务器内存/Redis/数据库 │ │
│ │ • 服务器需要维护状态,有资源消耗 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ Token │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 🎫 自包含的凭证(类似加密的身份证) │ │
│ │ • 数据本身包含用户信息 + 签名 │ │
│ │ • 服务器无需存储,验证签名即可 │ │
│ │ • 无状态,适合分布式系统 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘

三、工作流程对比

Cookie + Session 流程

┌─────────────────────────────────────────────────────────────────────┐
│ Cookie + Session 认证流程 │
│ │
│ 第1次请求(登录): │
│ ┌─────────┐ ┌─────────┐ │
│ │ 浏览器 │ │ 服务器 │ │
│ │ │ POST /login │ │ │
│ │ │ {user, pwd} │ │ │
│ │ │ ────────────────────────>│ │ │
│ │ │ │ 验证用户 │ │
│ │ │ │ 创建 Session │
│ │ │ │ 生成 JSESSIONID │
│ │ │ Set-Cookie: JSESSIONID │ │ │
│ │ │ │ │ │
│ │ │ │ 根据 ID 查 Session │
│ │ │ │ 返回数据 │ │
│ │ │ {data} │ │ │
│ │ │ │ │ │
│ │ │ │ 验证用户 │ │
│ │ │ │ 生成 Token(JWT) │
│ │ │ {token: "eyJhbG..."} │ │ │
│ │ │ │ │ │
│ │ │ │ 验证签名 │ │
│ │ │ │ 解析数据 │ (无需查存储) │
│ │ │ {data} │ │ │
│ │ │ <────────────────────────│ │ │
│ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────────────────────────┘

四、详细对比表
维度 Cookie Session Token (JWT)
存储位置 客户端浏览器 服务器端 客户端

数据内容 键值对(可存 Session ID 或 Token) 用户会话数据 加密的用户信息 + 签名

传递方式 自动携带(Cookie 头) 通过 Session ID 间接传递 手动添加(Authorization 头)

服务器状态 无状态 有状态 无状态

安全性 低(易 XSS) 中(依赖传输安全) 中高(签名验证)

性能 高 中(需查存储) 高(无需查存储)

分布式支持 需共享 Cookie 需 Redis 等共享 Session 天然支持

跨域支持 受限(需配置) 受限 灵活

有效期控制 可设置过期时间 可设置超时 内置过期时间

主动失效 可删除 Cookie 可销毁 Session 需黑名单机制

五、实际应用场景

场景 1:传统 Web 网站(Session + Cookie)
适合:后台管理系统、企业内网、表单提交频繁的网站
优点:实现简单、安全性好、服务端可控
缺点:服务器有状态、分布式需额外配置

场景 2:前后端分离(Token)
适合:SPA 应用、移动端 APP、微服务架构
优点:无状态、易扩展、跨域友好
缺点:Token 撤销困难、需防范盗用

场景 3:混合模式(Session + Token)
适合:需要兼顾多种客户端的场景
实现:
• Web 端:Session + Cookie(自动登录体验好)
• APP/第三方:Token(灵活传递)

六、总结:三者关系一句话

┌─────────────────────────────────────────────────────────────────────┐
│ │
│ Cookie 是📦盒子,用来装东西(Session ID 或 Token) │
│ │
│ Session 是🗄️服务器上的数据,需要 Cookie 里的 JSESSIONID 来查找 │
│ │
│ Token 是🎫自包含的凭证,可以放在 Cookie 里,也可以放在 Header 里 │
│ │
│ JSESSIONID 是 Session 的🔑钥匙,默认存放在 Cookie 中 │
│ │
└─────────────────────────────────────────────────────────────────────┘

您的情况总结

您的 Spring Boot 应用:
┌─────────────────────────────────────────────────────────────────┐
│ • 使用 Session 认证(不是纯 Token) │
│ • JSESSIONID 存放在 Cookie 中传递 │
│ • 第一次请求:无 Cookie → 无 JSESSIONID → 找不到 Session → 失败│
│ • 第二次请求:有 Cookie → 有 JSESSIONID → 找到 Session → 成功 │
│ │
│ 这是 Session 认证的正常流程,但不是 Token 认证的流程 │
└─────────────────────────────────────────────────────────────────┘

如需改为纯 Token 认证,需要修改 Spring Security 配置为 STATELESS 模式。

posted @ 2026-02-23 14:06  静水深耕,云停风驻  阅读(0)  评论(0)    收藏  举报