Cookie、Session、Token的三角恋
——基于小编自身粗略的理解:Cookie、Session、Token概念关系?如何保持用户登录态?
文章目录
Cookie
为什么有cookie
因为http是无状态的,每个请求都是独立的,服务器不知道这个请求是哪个用户的
这里就需要保持登录状态,即登陆一次,后面的请求就自动携带用户信息
所以浏览器就要想办法在每一次请求里加入用户名和密码,可以实现每次HTTP请求都自动携带数据给服务器的技术,即Cookie
具体概念
- 是什么:存储在浏览器中的小型文本文件(通常≤4KB)
- 存储内容:键值对数据(如:
user_id=123; session_id=abc123)
实现流程
- 浏览器第一次访问这个服务器,发生没有带cookie的请求
- 服务器会进行Cookie设置,也就是Set-Cookie,即返回的请求头中有Set-Cookie字段(如上图Set-Cookie的字段内容为name:技术蛋,Value:蛋产鸡)
- 浏览器收到这个Cookie之后会保存起来,之后的每一个请求都会自动附上这个Cookie
- Cookie是存放在浏览器的数据,打开浏览器也可以查看保存的Cookie
Cookie的格式
一个完整的Cookie长这样 (3部分:名称、值、各种属性)
name=value; Expires=日期; Max-Age=秒数; Domain=域名; Path=路径; Secure; HttpOnly; SameSite=策略
1.服务器设置Cookie返回给浏览器时
HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie: sessionid=abc123def456; Path=/; HttpOnly; Max-Age=86400
Set-Cookie: csrf_token=xyz789; Path=/; SameSite=Lax
Set-Cookie: theme=dark; Path=/blogdevteam; Expires=Wed, 21 Oct 2026 07:28:00 GMT
<!DOCTYPE html>
<html>...</html>
2.浏览器保存的Cookie数据
浏览器配置文件中
Set-Cookie: session=abc123;
Path=/; # 生效路径
Domain=.example.com; # 生效域名(可跨子域)
Expires=Mon, 15 Jan 2024 12:00:00 GMT; # 过期时间
Max-Age=3600; # 存活秒数
Secure; # 仅HTTPS发送
HttpOnly; # JS无法读取(防XSS)
SameSite=Lax; # 防CSRF攻击
还有两个cookie省略……
保存的键值对
| Cookie名称 | 值 | 属性 |
|---|---|---|
sessionid | abc123def456 | Path=/, HttpOnly, Max-Age=86400 |
csrf_token | xyz789 | Path=/, SameSite=Lax |
theme | dark | Path=/blogdevteam, Expires=2026-10-21 |
3.下次再访问时,浏览器会发送
只发送名称和值,属性部分供浏览器自己使用
GET /blogdevteam HTTP/1.1
Host: blog.youkuaiyun.com
Cookie: sessionid=abc123def456; csrf_token=xyz789; theme=dark
属性部分供浏览器自己使用,怎么使用?
Expires/Max-Age- “有效期”,告诉浏览器这个cookie的有效时间,过期后自动失效Set-Cookie: vip_card=VIP888; Expires=Wed, 31 Dec 2025 23:59:59 GMT #有效期至2025年12月31日23:59:59 Set-Cookie: vip_card=VIP888; Max-Age=2592000 #30天内有效,2592000秒 = 30天 × 24小时 × 60分钟 × 60秒没设置,则关闭浏览器这个cookie就消失!
Domain- “使用范围”,告诉浏览器这个cookie属于哪个域名下的Set-Cookie: user=alice; Domain=.brand.com #或 Set-Cookie: user=alice; Domain=shop.brand.com
Path- “店内区域限制”,告诉浏览器这个cookie属于哪个路径下的#通用(默认) Set-Cookie: vip=888; Path=/ #仅限特定区域 Set-Cookie: vip=888; Path=/vip-lounge
Secure- “安全通道要求”,,告诉浏览器这个cookie是通过HTTPS访问是才会发送Set-Cookie: session=secret123; Secure
HttpOnly- “防窥视保护”,信息被加密Set-Cookie: session_id=abc123; HttpOnly
能否访问 服务器 浏览器自动发送 JavaScript代码 有HttpOnly ✅ 能读 ✅ 自动带 ❌ 读不了 无HttpOnly ✅ 能读 ✅ 自动带 ✅ 能读
SameSite- “防外借规则”
SameSite=Strict- “绝不出借”,只能在同站请求中发送,从其他网站点击链接过来不发送CookieSet-Cookie: session=abc123; SameSite=Strict 例如
你在微博看文章 → 点击淘宝链接 微博 → 淘宝:不携带Cookie 需要重新登录淘宝
SameSite=Lax- “有限出借”,从其他网站点击链接过来发送Cookie。从其他网站发AJAX/fetch请求:不发送Cookie。从其他网站加载图片/iframe:不发送Cookie你在知乎 → 点击淘宝商品链接 知乎 → 淘宝:携带Cookie 自动登录淘宝,体验好!
SameSite=None- “允许外借”,必须搭配Secure
出现问题
由于用户名和密码都保存在浏览器里,很不安全,一旦被黑就泄露了信息,为了解决这个问题出现了Session这个新概念
Session
具体概念
Session是服务器端用来跟踪用户状态的机制
服务器为每个用户创建一个唯一的会话标识,并在服务器端存储与该会话相关的数据。(存在浏览器不安全)
一般存在内存
//在服务器存储Session数据
sessions[sessionId] = {
user_id: user.id,
username: user.name,
login_time: new Date(),
cart: []
};
//根据Session ID查找Session数据(查档案柜)
const sessionData = sessions[sessionId];
实现流程
- 浏览器将用户名和密码发送给服务器
- 服务器确认用户名和密码是对的,身份认证成功,创建一个Session ID和会话结束时间
- 服务器设置Cookie,并且把SessionID加入到Cookie里,再把会话结束时间设置为这个Cookie的有效期
- 浏览器拿到Cookie,保存
- 浏览器以后的访问都会带着这个存着session的cookie,直到浏cookie失效后,浏览器一般就会自行删除这个cookie,会话结束,用户就得重新输入用户名和密码
遇到的问题
1.每次请求进来都要通过sessionID查询数据库/内存,请求多的话,查询压力大(数据库)/存储sessionID的压力也大(内存)
2.如果是多台服务器,虽然可以分担sessionID查询压力,但是用户请求一多,请求就需要不同服务器来分担,这时候存储在A服务器的sessionID又要分享给B服务器,这样才能避免用户再次输入用户名和密码,但是这样共享session也不是办法
# 多服务器场景
服务器A: 用户登录,Session存在A的内存
服务器B: 用户请求过来,B不认识这个Session!
3.当服务器重启时,存在内存里的session数据就丢了
// Session存在内存里
const sessionStore = {
"abc123": {user: "张三", vip: true},
"def456": {user: "李四", vip: false}
};
// 服务器重启 → sessionStore = {} 空了!
// 所有用户会话丢失!
为了解决这个问题,出现了一种技术叫 JWT
Token
具体概念
Token指 JWT,JSON Web Token
JWT 就像一张加密的身份证
姓名:张三
余额:50元
等级:VIP
有效期:2024年底
防伪码:Wash#2024@!(特殊墨水印的)//政府秘钥生成
数据就在卡上!不再由服务器存储用户数据,而是交给用户自己拿着(相当于浏览器存储)
JWT的格式
JWT由三部分组成,用点号分隔:
头.载荷.签名
header.payload.signatur
这三部分就像三明治:
头部(面包).数据(馅料).签名(封口)
- 头部(Header) —— 加密身份证的类型说明
{
"alg": "HS256", // 加密算法:HMAC SHA256
"typ": "JWT" // 类型:JWT
}
Base64编码后:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
- 载荷(Payload) —— 证件上的真实信息
{
"sub": "1234567890", // 用户ID (subject)
"name": "张三", // 姓名
"admin": true, // 是否是管理员
"iat": 1516239022, // 签发时间 (issued at)
"exp": 1516242622 // 过期时间 (expiration)
}
Base64编码后:eyJzdWIiOiIxMjM0...
- 签名(Signature) —— “防伪印章”
// 使用头部指定的算法HMAC SHA256,加上header的编码、Payload的编码和服务器端的密钥,生成签名
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
"your-256-bit-secret" // 只有服务器知道的密钥
)
结果:SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
完整的JWT长这样:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. # 头部
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMiwiZXhwIjoxNTE2MjQyNjIyfQ. # 载荷
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c # 签名
具体流程
- 浏览器向服务器发送用户名和密码
- 服务器生成 JWT 发送给浏览器,服务器不用保存 JWT,只需保存 JWT 签名密文
- 浏览器以Cookie或Storage的形式进行存储,以后的每次请求都会把这个 JWT 发给服务器,用户就不需要写用户名和密码
- 服务器收到Token后
//服务器收到这样的请求
GET /api/profile
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
//开始验证
请求到达 → authMiddleware执行:
✓ 提取Token: "eyJhbGciOiJIUzI1NiIs..."
✓ 验证签名: 用JWT_SECRET验证 → 通过
✓ 检查过期: exp > 当前时间 → 未过期
✓ 查询用户: 从数据库查user_123456 → 用户存在
✓ 挂载用户: req.user = {id: "user_123456", ...}
→ 继续处理
- Token和Session类似,只是用户信息存储到了用户那边
三者关系
Session是诞生并且保存在服务器那边的,由服务器主导一切,而Cookie则是一种数据载体,把Session放在Cookie中发送到客户端那边,Cookie跟随HTTP的每个请求发送出去
Token是诞生在服务器,但保存在浏览器这边,由客户端主导一切,可以放在Cookie或Storage里面,持有Token就像持有"令牌"一样允许访问服务器
感谢
- b站蛋老师 Cookie、Session、Token究竟区别在哪?如何进行身份认证,保持用户登录状态?
- deepseek问答助手
1万+

被折叠的 条评论
为什么被折叠?



