Cookie-Session 方案 vs JWT Token 方案 超详细对比讲解
一、Cookie + Session 登录鉴权(服务端有状态方案)
1. 完整工作流程
步骤1:登录验证
用户提交账号密码,后端校验账号正确:
- 服务端生成唯一随机字符串
SessionID - 在服务端存储映射关系:
SessionID → 用户信息、过期时间、设备、权限- 单体:内存存储
- 分布式集群:Redis / MySQL 共享会话
- 通过 HTTP 响应头
Set-Cookie将 SessionID 下发给浏览器
Set-Cookie: SID=xxxxsessionidxxx; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=86400
步骤2:后续请求自动携带Cookie
浏览器规则:同域名下所有请求自动带上当前域名所有Cookie,无需前端手动处理。
请求自动带上:Cookie: SID=xxxxsessionidxxx
步骤3:后端鉴权
- 从请求 Cookie 取出 SID
- 查询 Redis/内存,判断 Session 是否存在、是否过期
- 存在则取出用户信息执行业务;不存在返回401未登录
步骤4:登出/过期
- 主动登出:后端删除Redis中对应Session记录,下次请求失效
- 被动过期:Redis设置TTL,超时自动清除会话
2. Cookie 关键安全属性(必配置)
| 属性 | 作用 |
|---|---|
| HttpOnly | JS无法通过document.cookie读取,防御XSS窃取会话 |
| Secure | 仅HTTPS协议下才发送Cookie,HTTP明文不传输 |
| SameSite=Lax/Strict | 跨站请求不会自动携带Cookie,防御CSRF攻击 |
| Path=/ | Cookie作用域整个网站,限制路径可缩小泄露范围 |
| Max-Age | 设置会话有效期 |
3. 优点
- 前端零成本:浏览器自动管理,不用手动存储、手动拼接请求头
- 数据存在服务端,前端只存ID,敏感信息不会暴露前端
- 可控性极强:后端随时删除Session实现强制下线、踢人
- 简单易上手,传统框架原生支持(Spring Session、PHP Session)
- CSRF配合防护后安全性很高
4. 缺点
-
服务端有状态
集群多台服务器部署时,必须做Session共享(Redis),否则负载均衡分发到不同机器会登录失效;扩容成本更高。 -
跨域限制严重
Cookie遵循同源策略,前端分离项目(前端域名a.com,后端api.b.com)默认无法携带Cookie,需要后端配置CORS +withCredentials,小程序、APP跨端兼容麻烦。 - CSRF 攻击风险
第三方钓鱼网站可构造跨站请求,浏览器自动带上本站Cookie,必须额外开发CSRF Token。
备注: - 移动端适配差
APP、小程序、第三方客户端不支持浏览器Cookie机制,无法直接使用。
5. 适用场景
传统单体后台管理系统、纯服务端渲染网站(JSP/Thymeleaf/PHP模板)、内部OA系统。
6. 配套安全方案:CSRF Token
因为Cookie自动携带,跨站伪造请求会带上有效会话,解决方案:
- 页面加载时后端生成随机CSRF Token存入Session
- 前端将Token存在localStorage或表单隐藏域
- 所有修改数据接口(POST/PUT/DELETE)请求头携带
X-CSRF-Token - 后端同时校验SessionID和CSRF Token是否匹配
二、JWT(JSON Web Token)无状态令牌方案
1. JWT 结构说明
三段用 . 分隔的 Base64URL 字符串,整体无加密,仅签名防篡改
Header.Payload.Signature
-
Header 头部(算法)
Base64编码JSON,指定签名算法,常用 HS256(对称密钥)、RS256(非对称公私钥){"alg":"HS256","typ":"JWT"} -
Payload 载荷(业务数据)
存放声明信息,分为标准声明和自定义业务字段⚠️ 仅Base64编码,可直接解码查看,禁止存放密码、银行卡等敏感数据
标准字段:
-iss:签发者
-exp:过期时间戳(必填)
-sub:用户唯一标识
-iat:签发时间
自定义:userId、role、username等 -
Signature 签名(防篡改核心)
公式:HMACSHA256(base64(Header) + "." + base64(Payload), 密钥)
后端校验时使用同一密钥重新计算签名,和传入Token签名对比,不一致说明数据被篡改,直接拒绝。
2. JWT 完整登录流程(标准双Token方案:Access + Refresh)
单Token存在无法主动注销的缺陷,生产环境一律使用双令牌模式
1)登录阶段
账号密码校验通过,后端生成两个令牌:
- AccessToken(短期,5~30分钟):接口鉴权使用,带用户信息
- RefreshToken(长期,7~30天):存入Redis/数据库,仅用于刷新AccessToken,不参与业务鉴权
返回给前端,前端存储:
- AccessToken:localStorage / sessionStorage
- RefreshToken:推荐HttpOnly Cookie存储(提升安全)
2)业务请求鉴权
前端每次接口手动在请求头携带:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
后端处理:
- 截取Bearer后的JWT字符串
- 使用密钥校验签名是否合法(判断是否被篡改)
- 校验exp过期时间
- 校验通过直接解析Payload获取用户ID、权限,无需查询存储
3)Token过期无感刷新
前端拦截接口401过期响应,自动调用刷新接口:
- 提交RefreshToken
- 后端查询Redis判断RefreshToken是否有效、未被注销
- 有效则生成新AccessToken返回前端,旧AccessToken继续用到过期
- RefreshToken失效则跳转登录页
4)登出/强制下线
单纯JWT无状态无法失效已签发未过期Token,依靠RefreshToken管控:
- 用户登出:后端删除Redis中该用户的RefreshToken
- 后台强制踢人:清除对应RefreshToken,用户无法刷新新Token,AccessToken短期过期后自动下线
- 高危场景补充:Redis黑名单存储未过期但作废的AccessToken,短期拦截
3. JWT 优点
-
完全无状态,分布式友好
鉴权只校验签名,不需要服务端存储会话,多机器集群、微服务无需共享存储,扩容简单。 - 天然支持跨域、多端
Token放在请求Header,不受Cookie同源限制;网页、APP、小程序、第三方客户端通用。 - 自带用户信息,减少DB查询
Payload内置用户ID、角色权限,高频接口不用每次查库获取用户身份。 - 适配微服务、单点登录SSO
统一身份中心签发JWT,所有微服务共用一套密钥校验,不用会话共享。
4. JWT 缺点
-
无法立即失效(原生缺陷)
只要AccessToken未过期、签名合法就有效,单纯单JWT方案做不到强制下线,必须搭配RefreshToken+Redis黑名单弥补。 - Payload明文可解码,不能存敏感数据
Base64只是编码不是加密,任何人拿到Token都能读出里面所有信息。 - Token体积大,增加网络开销
相比短SessionID,JWT字符串很长,每次请求携带会增加带宽消耗。 - 刷新逻辑复杂,前端需要封装无感刷新拦截器
要处理401重试、并发刷新锁、过期跳转等逻辑,开发成本高于Cookie-Session。 - XSS窃取风险更高
多数项目AccessToken存在localStorage,JS可读取,XSS漏洞会直接盗取Token;Cookie的HttpOnly可规避该问题。
5. 适用场景
前后端分离SPA网站、小程序、APP、微服务、第三方开放登录、跨域项目。
6. JWT安全优化手段
- 使用短期AccessToken,降低被盗后的有效期风险
- RefreshToken存入HttpOnly Cookie,避免前端JS读取
- 非对称加密RS256,私钥签发、公钥校验,密钥泄露风险更低
- 绑定设备指纹,同一RefreshToken仅限登录设备使用
- 增加黑名单机制,支持主动注销
三、Cookie-Session vs JWT 核心横向对比
| 对比维度 | Cookie + Session | JWT(Access+Refresh) |
|---|---|---|
| 状态 | 有状态,服务端存储Session映射 | 半无状态,仅RefreshToken存库,AccessToken无状态 |
| 分布式集群 | 需要Redis共享Session,架构复杂 | 天然分布式友好,微服务首选 |
| 跨域/多端 | 同源限制,APP/小程序兼容差 | 无跨域限制,全端通用 |
| 前端存储 | 浏览器自动管理,无JS操作 | 前端手动存储,手动添加请求头 |
| 强制下线 | 立即生效,直接删除Session | 无法立刻失效AccessToken,依赖RefreshToken销毁 |
| 数据安全性 | 用户数据存在服务端,前端仅ID | 用户信息明文编码在Token,不可存敏感字段 |
| XSS风险 | HttpOnly Cookie可完全规避窃取 | localStorage存AccessToken易被XSS盗取 |
| CSRF风险 | 存在,必须额外实现CSRF Token | 无CSRF风险(Header手动携带,不会自动跨站携带) |
| 请求体积 | SessionID很短,开销小 | JWT字符串长,带宽消耗更大 |
| 开发复杂度 | 后端简单,前端零逻辑 | 前端需封装拦截、刷新逻辑,复杂度更高 |
四、生产环境选型建议
- 传统服务端渲染、单体后台、内网系统 → Cookie-Session + CSRF
- 前后端分离、小程序、APP、微服务、跨域项目 → JWT Access + Refresh Token
- 金融、高安全管控系统(需要实时踢人):两种方案均可,优先Redis自定义短Token(兼顾可控与跨端)