【一篇解答登录态】Cookie、Session、Token的概念、与区别?如何保持登录态?

Cookie、Session、Token的三角恋

——基于小编自身粗略的理解:Cookie、Session、Token概念关系?如何保持用户登录态?

Cookie

为什么有cookie

因为http是无状态的,每个请求都是独立的,服务器不知道这个请求是哪个用户的

这里就需要保持登录状态,即登陆一次,后面的请求就自动携带用户信息

所以浏览器就要想办法在每一次请求里加入用户名和密码,可以实现每次HTTP请求都自动携带数据给服务器的技术,即Cookie

具体概念

  • 是什么:存储在浏览器中的小型文本文件(通常≤4KB)
  • 存储内容:键值对数据(如:user_id=123; session_id=abc123

实现流程

bcd1f5c1e9d52c8ab8e786bf5f67b93
  • 浏览器第一次访问这个服务器,发生没有带cookie的请求
  • 服务器会进行Cookie设置,也就是Set-Cookie,即返回的请求头中有Set-Cookie字段(如上图Set-Cookie的字段内容为name:技术蛋,Value:蛋产鸡)
  • 浏览器收到这个Cookie之后会保存起来,之后的每一个请求都会自动附上这个Cookie
  • Cookie是存放在浏览器的数据,打开浏览器也可以查看保存的Cookie
bcd1f5c1e9d52c8ab8e786bf5f67b93

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名称属性
sessionidabc123def456Path=/, HttpOnly, Max-Age=86400
csrf_tokenxyz789Path=/, SameSite=Lax
themedarkPath=/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 - “绝不出借”,只能在同站请求中发送,从其他网站点击链接过来不发送Cookie
    Set-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];

实现流程

6cdacb6272c5a9d7bd9dd92a463fd02
  • 浏览器将用户名和密码发送给服务器
  • 服务器确认用户名和密码是对的,身份认证成功,创建一个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   # 签名
43df9c51d2a56d8fb237a02560080ec

具体流程

c9c5ab79c332ed8d90d261aac382647
  • 浏览器向服务器发送用户名和密码
  • 服务器生成 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就像持有"令牌"一样允许访问服务器


感谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值