【计算机网络】一篇带你弄懂Cookie, Session, Token!
【计算机网络】万字详解,一篇带你弄懂Cookie, Session, Token!一、Cookie1.1 Cookie 简介1.2 Cookie 的工作原理1.3 Cookie 的常见用途1.4 如何使用 Cookie1.5 Cookie 的安全性与限制1.6 Cookie 的优缺点小结二、Session2.1 Session 简介2.2 Session 的工作机制与原理2.3 Session 的
【计算机网络】万字详解,一篇带你弄懂Cookie, Session, Token!
文章目录
一、Cookie
1.1 Cookie 简介
Cookie 是一种由服务器发送并保存在用户浏览器端的小型文本数据,通常用于记录用户身份、偏好设置和浏览活动等信息。它的最大容量约为 4KB(大多数浏览器支持的单个 Cookie 最大大小为 4096 字节),且只能在客户端本地存储与传输。
简单来说,Cookie 就像是网站“写给你浏览器的一张便签纸”,下次你再访问该网站时,浏览器会自动带上这张“便签纸”,帮助服务器识别你是谁。
1.2 Cookie 的工作原理
Cookie 的本质是浏览器与服务器之间自动传递的一段文本信息。它的整个生命周期包括创建、存储、发送和删除,典型工作流程如下:
-
创建 Cookie(Set-Cookie 响应头)
当用户第一次访问网站时,服务器根据业务需要生成 Cookie,并在 HTTP 响应头中通过
Set-Cookie
字段发送给浏览器。示例:HTTP/1.1 200 OK Content-Type: text/html Set-Cookie: sessionid=abc123; Expires=Wed, 21 Jul 2025 07:28:00 GMT; Path=/; HttpOnly; Secure
这个例子里,服务器告诉浏览器:
- Cookie 名称:
sessionid
- Cookie 值:
abc123
- 过期时间:2025年7月21日
- 作用路径:整个网站
- 仅限服务器访问(
HttpOnly
) - 仅在 HTTPS 传输(
Secure
)
这样浏览器会将
sessionid=abc123
保存下来。 - Cookie 名称:
-
浏览器本地保存 Cookie
浏览器接收到
Set-Cookie
后,会将其存储在本地 Cookie 存储区(一般是浏览器配置文件中的数据库或文本文件),并在指定有效期内保留。若未设置Expires
或Max-Age
,Cookie 默认为会话 Cookie,关闭浏览器即失效。 -
发送 Cookie(请求头中自动携带)
当用户再次访问该网站或在该网站内跳转页面时,浏览器会自动将与当前 URL 匹配的 Cookie放入 HTTP 请求头
Cookie
中发送给服务器。例如:GET /profile HTTP/1.1 Host: www.example.com Cookie: sessionid=abc123
注意:
- 浏览器只会携带与当前域名和路径匹配的 Cookie。
- 如果有多个 Cookie,会以分号分隔。
-
服务器读取 Cookie
服务器收到请求后,通过解析请求头
Cookie
字段,提取出之前发给用户的 Cookie,从而识别用户身份或状态。例如:- 根据
sessionid
查询服务器数据库中的会话信息。 - 判断用户是否登录。
- 获取用户偏好设置。
- 根据
-
更新或删除 Cookie
在服务器处理完请求后,也可以再次通过
Set-Cookie
指令:- 更新 Cookie(比如延长过期时间)。
- 删除 Cookie(通过设置过期时间为过去的时间)。
例如删除 Cookie:
Set-Cookie: sessionid=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/
浏览器在接收到这个响应后,会立刻移除本地的
sessionid
Cookie。
注意:
Cookie 的匹配规则:
- 域名(Domain):必须与当前访问的域名一致或在指定的子域名范围内。 * 路径(Path):URL 必须在 Cookie
指定的路径范围内。 * 安全属性(Secure):如果设置了 Secure,只有 HTTPS 请求才会携带 Cookie。自动携带机制:
- Cookie 不需要开发者手动在请求里加,浏览器会在每次请求中自动携带。
生命周期:
- 会话 Cookie:关闭浏览器即失效。 * 持久 Cookie:到指定过期时间失效。
举例:一次完整的 Cookie 流程
假设你登录一个网站:
-
登录请求:
POST /login
服务器验证成功后响应:
Set-Cookie: token=xyz789; Path=/; HttpOnly; Expires=Fri, 01 Aug 2025 12:00:00 GMT
-
浏览器保存:
保存token=xyz789
。 -
访问个人中心:
GET /profile Cookie: token=xyz789
服务器通过 token 验证身份。
-
退出登录:
GET /logout
响应:
Set-Cookie: token=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/
浏览器删除 Cookie。
网站能基于上述简单流程完成 Cookie 实现“状态保持”和“用户识别”。
1.3 Cookie 的常见用途
- 保持登录状态: 当用户登录后,网站可以将登录状态信息(如 Session ID)保存在 Cookie 中。下次访问时,用户不需要重新登录,服务器通过Cookie 自动识别用户身份。
- 记住用户偏好: 如用户选择的语言、主题样式、阅读模式等设置,都可以通过 Cookie 存储,在用户下次访问时自动加载。
- 购物车功能: 在未登录状态下,用户将商品添加到购物车,网站通过 Cookie 存储这些商品信息,使得用户下次访问仍能看到购物车内容。
1.4 如何使用 Cookie
以下为JavaScript 操作示例
设置 Cookie:
// 设置一个名为 username 的 Cookie,值为 "Tom",过期时间为7天
document.cookie = "username=Tom; expires=Fri, 20 Jul 2025 12:00:00 UTC; path=/";
读取 Cookie:
// 获取所有 Cookie 字符串
let cookies = document.cookie;
console.log(cookies); // 输出:username=Tom
删除 Cookie:
// 将 Cookie 的过期时间设置为过去,即可删除
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/";
1.5 Cookie 的安全性与限制
安全性问题:
- 容易被劫持:如果未使用 HTTPS,Cookie 数据在传输过程中可能被中间人攻击(MITM)。
- 容易被 XSS 攻击访问:若未设置
HttpOnly
,Cookie 可被 JavaScript 读取,从而造成信息泄露。
常用的安全属性:
HttpOnly
:防止前端 JavaScript 访问 Cookie。Secure
:仅在 HTTPS 下传输 Cookie。SameSite
:防止跨站请求伪造(CSRF)攻击。
限制:
- 单个 Cookie 最大容量约为 4KB。
- 每个域名最多可存储约 20 个 Cookie。
- Cookie 会随每次请求发送,占用带宽。
1.6 Cookie 的优缺点小结
优点 | 说明 |
---|---|
简单易用 | 浏览器自动管理,开发者只需配置即可 |
支持跨页面存储 | 可以在同一域名下多个页面共享 |
持久化 | 可设置过期时间,实现长时间保存 |
缺点 | 说明 |
---|---|
容量有限 | 单个 Cookie 体积小,无法存储大量数据 |
安全性较低 | 易受 XSS、CSRF 和中间人攻击威胁 |
每次请求自动发送 | 占用带宽,不适合频繁变化的大数据 |
二、Session
2.1 Session 简介
Session(会话)是服务器用于记录用户状态信息的一种机制。它通过在服务器端存储数据,配合客户端的标识(通常是 Cookie 中的 Session ID),在多次请求之间跟踪同一个用户的访问状态。相比 Cookie 把数据直接保存在浏览器里,Session 把数据放在服务器上,客户端只保存一个Session ID。这样更安全,不容易被用户篡改。
2.2 Session 的工作机制与原理
Session 的核心目标就是在一次次 HTTP 请求之间维持同一个用户的状态,实现“同一个用户多次访问时能被识别”。
由于 HTTP 协议是无状态的(每个请求彼此独立),就需要 Session 来补充状态管理。
下面分步骤详细讲解:
1. 用户首次访问服务器
-
用户第一次访问网站(如访问登录页)时,服务器检测到当前请求中没有携带任何 Session ID。
-
服务器会:
- 创建一个新的 Session 对象(一般保存在服务器内存或 Redis 中)。
- 为这个 Session 分配一个唯一的 Session ID(例如:
ABCDEF1234567890
)。
这个 Session ID 是用来标识这份 Session 数据的“钥匙”。
2. 服务器把 Session ID 返回给浏览器
-
服务器通过 HTTP 响应头把 Session ID 返回给客户端。
-
一般用
Set-Cookie
指令:Set-Cookie: JSESSIONID=ABCDEF1234567890; Path=/; HttpOnly
解释:
JSESSIONID=...
:Session ID 的名字和内容。Path=/
:表示这个 Cookie 在整个网站有效。HttpOnly
:防止 JavaScript 读取,增加安全性。
浏览器接收到响应后,会自动把这个 Cookie 存储在本地。
3. 浏览器保存 Session ID
- 浏览器把
JSESSIONID
保存在 Cookie 中。 - 如果这个 Cookie是会话 Cookie(没有设置
Expires
或Max-Age
),那么只在浏览器进程中存在,关闭浏览器后就失效。 - 如果配置了持久化时间(不常用),则浏览器重启后依然保留。
4. 浏览器后续请求自动带上 Session ID
-
当用户再次访问同一网站时:
-
浏览器会在请求头自动带上这个 Cookie:
Cookie: JSESSIONID=ABCDEF1234567890
-
-
无需开发者手动设置。
5. 服务器根据 Session ID 找到对应 Session
-
服务器接收到请求后,会:
- 读取
Cookie
中的JSESSIONID
。 - 在服务器端 Session 存储(内存或数据库)中,根据这个 Session ID 找到对应的 Session 数据。
- 读取
-
如果找不到(过期或被销毁),服务器会重新创建一个新的 Session。
Session 与 Cookie 的关系(JSESSIONID)
很多人容易混淆 Cookie 和 Session,这里特别说明:
Cookie | Session |
---|---|
存储位置:浏览器 | 存储位置:服务器 |
数据:可以直接存储业务数据(如用户名) | 数据:业务数据放在服务器,浏览器只存 Session ID |
安全性:容易被伪造 | 安全性:只要 Session ID 保密,数据不会被篡改 |
JSESSIONID 就是 Session 的“身份证号码”,用来在客户端和服务器之间“对号入座”。
URL 重写
如果浏览器禁用了 Cookie(或不支持 Cookie),Session 也可以通过 URL 传递 Session ID,例如:
https://www.example.com/shop/list;jsessionid=ABCDEF1234567890
这种方式叫URL 重写,不安全也不常用(容易泄露 Session ID)。
2.3 Session 的存储方式与生命周期
Session 本质上是一份服务器端的“数据字典”,以 Session ID 作为关键字保存对应的数据。
常见存储方式:
1. 内存(默认方式)
-
Session 通常保存在服务器的内存中(如 Tomcat 内存)。
-
特点:
- 访问速度非常快。
- 适合小型单体应用。
-
缺点:
- 服务器重启会丢失所有 Session。
- 不支持多台服务器共享 Session(集群环境)。
2. 文件存储
-
Session 会序列化后写入服务器的硬盘文件中。
-
特点:
- 重启服务器也能恢复 Session。
- 适合 Session 量较小的系统。
-
缺点:
- 文件读写性能比内存差。
- 部署多节点需要共享存储或同步。
3. 数据库存储
-
将 Session 数据保存在关系型数据库(如 MySQL)。
-
特点:
- 跨服务器共享 Session。
- 可以持久化历史数据。
-
缺点:
- 数据库连接压力大。
- 性能比内存和 Redis差,需优化。
4. 分布式缓存(如 Redis、Memcached)
-
将 Session 存入 Redis 集群,是目前最流行的高并发解决方案。
-
特点:
- 支持分布式共享。
- 高并发读写性能。
- 内存存储,速度快。
-
缺点:
- 需要额外部署 Redis。
- Session 需序列化和反序列化。
Session 的生命周期由服务器管理,包括以下几个阶段:
1. 创建
-
当用户第一次请求需要状态跟踪的资源时(如访问登录页),服务器通过:
request.getSession();
创建一个新的 Session 对象。
-
同时分配一个唯一的 Session ID。
2. 活动更新
- 每一次请求,Session 的最后访问时间会被更新。
- 如果用户持续访问,Session 会一直处于活跃状态,不会过期。
3. 过期与销毁
Session 会在以下几种情况下销毁:
-
空闲超时自动失效
-
如果在指定时间内没有访问,服务器会自动清理 Session。
-
默认时间:30分钟(Tomcat)。
-
可通过
web.xml
配置:<session-config> <session-timeout>30</session-timeout> </session-config>
表示30分钟无操作即失效。
-
-
手动销毁
-
程序调用:
session.invalidate();
会立即销毁 Session,清理所有数据。
-
-
服务器重启
- 如果 Session 存在于内存,重启服务器会清空。
- 若使用 Redis/数据库等持久化存储,则可恢复。
2.4 Session 常用方法示例
以 Java Servlet 为例,在 Java Web 中,HttpSession
接口提供一系列方法,方便开发者操作 Session。
以下示例基于 Servlet:
1. 获取 Session
HttpSession session = request.getSession();
- 如果 Session 不存在,创建新的 Session。
- 如果已有 Session,直接返回。
2. 判断 Session 是否存在
如果只想获取现有 Session,不创建新 Session:
HttpSession session = request.getSession(false);
if (session == null) {
// Session不存在
}
3. 存储数据
把数据保存在 Session 中,类似 key-value:
session.setAttribute("username", "Alice");
session.setAttribute("role", "admin");
- 键是字符串。
- 值可以是任意对象(会被序列化)。
4. 获取数据
获取存储在 Session 中的数据:
String username = (String) session.getAttribute("username");
如果没有对应的键,会返回 null
。
5. 删除数据
移除 Session 中的某个属性:
session.removeAttribute("username");
6. 手动销毁 Session
立即清空 Session 中所有数据并让其失效:
session.invalidate();
- 用户再次请求时,会创建一个新的 Session。
7. 获取 Session ID
获取当前 Session 的唯一标识:
String sessionId = session.getId();
- 常用于调试或日志。
8. 判断 Session 是否是新创建
有时候需要判断当前 Session 是否是刚创建的:
boolean isNew = session.isNew();
if (isNew) {
// 刚创建的Session
}
9. 设置 Session 最大不活动时间
动态设置超时时间(单位:秒):
session.setMaxInactiveInterval(600); // 10分钟
- 0 表示永不超时。
- -1 表示跟随服务器默认。
10. 示例:登录流程
// 登录校验成功
HttpSession session = request.getSession();
session.setAttribute("loginUser", "alice");
// 以后只要有Session就表示已登录
11. 示例:退出登录
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}
当然,下面我来详细写三、Token部分:
三、Token
3.1 Token 简介
Token(令牌)是一段由服务器生成的字符串,用来代表用户的身份信息或访问权限。Token 在认证和授权中常被用作用户身份的凭证,与传统 Session 不同,Token 不依赖服务器记录状态,而是通过签名和加密保障安全性。
3.2 Token 的无状态性与自包含性
无状态性 (Stateless)
Token 认证最大的特点是无状态:
- 服务器不需要保存每个用户的登录信息或会话数据。
- 每一次请求只需要验证 Token 本身是否合法。
自包含性 (Self-contained)
Token 中包含用户的必要信息(如用户 ID、权限、过期时间等),即自包含:
- 不必再去数据库查找。
- 签名保证内容未被篡改。
这种机制非常适合分布式系统或微服务。
3.3 Token 的工作流程
下面是一个典型的基于 Token 的身份认证和授权流程,分为登录签发、客户端存储与请求携带、服务器验证三大步骤。
1.用户登录与 Token 签发
这是 Token 认证的第一步,也就是获取 Token的过程:
(1)用户发起登录请求
-
用户在客户端(浏览器、APP等)输入账号密码。
-
客户端将用户名、密码通过 HTTPS POST 请求发送给后端:
POST /api/login Content-Type: application/json { "username": "alice", "password": "password123" }
(2)服务器验证用户凭证
- 服务器查询数据库检查用户名和密码是否正确。
- 如果验证失败,返回401(Unauthorized)。
(3)生成 Token
-
验证成功后,服务器根据用户信息生成一个 Token。
-
通常使用 JWT(JSON Web Token),内容包括:
sub
: 用户ID或用户名(Subject)iat
: 签发时间(Issued At)exp
: 过期时间(Expiration)- 其他自定义字段,如用户角色(role)、权限(scope)
-
最后,服务器根据约定的**密钥(Secret Key)**进行签名,防止篡改。
(4)返回 Token
-
服务器将 Token 放在响应体中返回:
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }
2.客户端存储与请求携带
获取到 Token 后,客户端要安全存储并在每次请求时携带:
(1)存储位置
-
Web端常用:
LocalStorage
(浏览器本地存储,持久化)SessionStorage
(浏览器会话存储,关闭浏览器失效)HttpOnly Cookie
(更安全,不可通过 JavaScript 访问)
-
移动端常用:
- 本地数据库(SQLite)
- 安全存储组件
如果需要抵御 XSS 攻击,优先考虑
HttpOnly Cookie
。
(2)每次请求携带 Token
-
客户端在调用受保护 API 时,要在 HTTP Header 中加
Authorization
:GET /api/user/profile Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
-
“Bearer”表示使用令牌认证。
(3)请求示例(JavaScript fetch)
fetch('/api/user/profile', {
method: 'GET',
headers: {
'Authorization': 'Bearer ' + token
}
})
服务器就可以识别该请求身份。
3.服务器验证
服务器在收到每个请求时,都会对 Token 进行严格验证:
(1)从请求头提取 Token
- 读取
Authorization
请求头。 - 判断格式是否正确(前缀是
Bearer
)。
(2)解析 Token
-
将 Token 拆解成:
- Header
- Payload
- Signature
-
Base64 解码 Header 和 Payload。
(3)验证签名
- 服务器使用相同的密钥(或公钥)重新生成签名。
- 与 Token 中的签名比对,防止伪造。
(4)校验有效期
-
比较
exp
(过期时间)与当前时间:- 如果已过期,返回 401 Unauthorized。
- 如果未过期,继续处理请求。
(5)读取用户信息
- 从 Payload 中提取
sub
(用户ID)和其他信息。 - 可根据需要查询数据库进一步确认状态(如是否封禁)。
(6)处理业务逻辑
- 如果验证成功,执行请求对应的操作(查询、更新等)。
- Token 验证完全由服务器完成。
- 验证过程不依赖 Session,不占用内存。
- 完全“无状态”。
3.4 Token 的常见类型
下面介绍几种常见的 Token 类型:
1. JWT(JSON Web Token)
-
最流行的 Token 格式。
-
基本结构:
Header.Payload.Signature
- Header:声明算法类型
- Payload:数据(如用户信息)
- Signature:签名
-
自包含、易解析。
示例:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
2. OAuth 2.0 Token
主要用于授权(第三方登录、API访问):
- Access Token: 访问受保护资源时携带,短有效期。
- Refresh Token: 用于刷新新的 Access Token,有较长有效期。
常用于:
- 微信、GitHub 登录。
- 微服务之间授权。
3. API Token
- 一般为随机字符串。
- 用于接口访问授权。
- 不一定包含用户信息,通常在数据库中验证。
示例:
123456abcdef7890
3.5 Token 的应用场景
Token 在现代 Web 和分布式系统中用途非常广泛,解决了很多传统 Session/Cookie 模式的局限性。
1.前后端分离
过去的传统 Web 应用(如 JSP、PHP)由服务器渲染页面,直接使用 Session 保存用户状态。在现代架构中,前端与后端完全分离,前端用 Vue、React、Angular 编写 SPA(Single Page Application),后端仅提供 RESTful API 或 GraphQL。
为什么适合用 Token:
- Session 必须依赖服务器内存/存储,会话信息需要和前端共享,而 Token 是自包含、无状态的。
- 客户端只需在本地保存 Token(LocalStorage / Cookie),每次请求带上 Token 即可,无需与后端建立状态会话。
流程:
- 前端登录后,从后端获取一个 JWT Token。
- 将 Token 保存在
localStorage
(或安全 Cookie)。 - 后续通过
Authorization: Bearer <token>
请求接口。 - 后端仅通过 Token 验证身份,不依赖 Session。
2.单点登录(SSO:Single Sign-On)
企业或组织内部有多个系统(门户、OA、CRM等),用户只需登录一次,就可以在不同系统之间共享身份。
- 中央认证服务器颁发一个 Token。
- 各子系统接收到 Token 后验证签名与有效期,确认用户身份。
3.跨域认证
前端和后端分别部署在不同域名(如
api.example.com
和www.example.com
),传统 Cookie 依赖同源策略,跨域使用困难。
- Token 通过请求头携带,不依赖 Cookie。
- 跨域也能验证身份,只需配置 CORS。
4.微服务架构
后端拆分为多个微服务,每个微服务负责部分业务。=
- 请求先到 API 网关。
- 网关验证 Token。
- 将用户信息(如 userId)传递到下游微服务。
- Token中可封装权限、角色等信息。=
5.移动端、第三方接入
移动端与后端交互没有 Cookie,Token成为身份验证的标准方式。
- 提供 API Token,允许开发者调用 API。
- 通过签名和过期机制保证安全。
3.6 Token 的优缺点小结
优点 | 说明 |
---|---|
无状态 | 服务器无需存储会话数据,减轻内存/存储压力。 |
灵活 | 天生支持分布式部署和跨域调用,适合微服务、前后端分离场景。 |
自包含 | Token 内含用户信息、权限、过期时间等,可减少数据库或缓存查询。 |
缺点 | 说明 |
---|---|
无法主动失效 | 颁发后在有效期内有效,需额外设计黑名单/撤销列表来提前失效。 |
泄露风险高 | 一旦被截获,攻击者可以在有效期内随意使用,需配合 HTTPS、短过期时间。 |
体积较大 | 比传统 Session ID(短字符串)要大,尤其是带 payload 的 JWT。 |
四、Cookie、Session、Token 的比较
4.1 存储位置对比
技术 | 数据存储位置 |
---|---|
Cookie | 客户端(浏览器),通过请求头自动携带 |
Session | 服务器端(内存、数据库、缓存等),客户端仅保存 Session ID |
Token | 客户端(LocalStorage/Cookie),服务器不保存状态 |
4.2 安全性对比
技术 | 安全性特点 |
---|---|
Cookie | 数据暴露在客户端,易被查看或篡改;需配合 HttpOnly、Secure 等属性提高安全 |
Session | 数据保存在服务器,相对安全;Session ID 若被盗,仍可能被伪造请求 |
Token | 自包含、签名验证,防篡改;若泄露则有效期内可被利用;需 HTTPS、短有效期防护 |
4.3 性能与扩展性对比
技术 | 性能与扩展性说明 |
---|---|
Cookie | 不依赖服务器存储,性能影响小;数据随每个请求发送,增加带宽开销 |
Session | 服务端需维护 Session,单机性能高;分布式部署需做共享或粘性会话 |
Token | 无状态,适合分布式和微服务架构;每次验证 Token,可能增加 CPU 负担 |
4.4 适用场景对比
技术 | 典型适用场景 |
---|---|
Cookie | 简单用户偏好存储(主题、语言)、低安全要求的状态数据 |
Session | 中小型系统、登录态保持(如传统单体应用) |
Token | 前后端分离、移动端、跨域、微服务、单点登录(SSO)等现代场景 |
4.5 优缺点总结
技术 | 优点 | 缺点 |
---|---|---|
Cookie | 简单易用,浏览器自动携带 | 容易被篡改、存储空间有限、安全性差 |
Session | 安全性好、可存储任意对象 | 占用服务器资源、分布式扩展复杂 |
Token | 无状态、支持跨域分布式、灵活 | 无法主动失效、泄露风险高、体积大 |
当然,下面给你写一个4.6 三者之间的关系,我会尽量详细、清晰、全面地阐述:
4.6 三者之间的关系
Cookie、Session、Token虽然都是在多次HTTP请求中维持用户状态的机制,但它们相互配合、各司其职,经常组合使用而不是完全替代。可以从底层原理、演化背景、协作方式来理解三者关系:
1.Cookie 是最基础的状态保持手段
- HTTP 是无状态协议,每次请求服务器都无法识别是谁发的。
- Cookie的出现,就是在浏览器端存储小段文本数据(键值对),并在请求时自动带到服务器,让服务器“记住”客户端。
- Cookie既可以直接保存用户数据(如userId、token等),也可以作为Session ID的载体。
示例:
Cookie: sessionid=abcd1234
2.Session 是在服务器端“保存用户状态”的方案
-
Session实际上就是服务器用来保存用户状态的容器。
-
服务器在创建Session时,会生成一个唯一的Session ID。
-
这个Session ID必须让客户端带回来,最常见的就是放进Cookie里(如
Set-Cookie: JSESSIONID=...
)。 -
所以,Session和Cookie往往配合使用:
- Cookie负责保存和传递Session ID。
- Session存储用户状态和业务数据。
-
如果不用Cookie,也可以把Session ID放在URL参数里(URL重写),但这不安全。
简化流程:
客户端 → 请求 → 服务器创建Session → 返回带Session ID的Cookie → 客户端保存 → 下次请求带Session ID → 服务器根据ID找到Session。
3.Token 是在“无状态化”趋势下的演进产物
-
随着前后端分离、移动应用、微服务的发展,传统Session遇到服务器负载、分布式共享问题。
-
Token(特别是JWT)提出了无状态认证:所有需要的信息都放在Token里,服务器不再存储会话。
-
Token本质上依然要在客户端“保存和传递”,这部分往往依赖Cookie或者LocalStorage:
- 如果用Cookie存Token,浏览器会自动在请求中带上。
- 如果用LocalStorage,需在每次请求时在Header里手动附带。
-
所以,Token也经常和Cookie结合:只是Cookie里保存的不是Session ID,而是Token。
示例:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6...
4.从演化脉络来看
-
Cookie:
- 最原始的解决方案,直接把状态存在浏览器里。
-
Session:
- 把状态放到服务器里,用Cookie传Session ID。
-
Token:
- 把状态又放回客户端(Token里自包含用户信息),但多了签名、加密,保证安全性和一致性。
这是一种演化和适应:
- Cookie:单纯的客户端状态。
- Session:客户端-服务器状态分离,依赖Session ID。
- Token:彻底无状态,服务器只验证签名。
5.三者组合使用的典型方式
在实际应用中,三者经常组合使用,例如:
-
Session + Cookie:
- 传统单体应用最常见,登录后服务器建Session,客户端用Cookie带Session ID。
-
Token + Cookie:
- 把Token(如JWT)放在HttpOnly Cookie里,自动携带且防XSS。
-
Token + LocalStorage:
- 前端自己存Token,每次请求在Header里手动携带。
对比维度 | Cookie | Session | Token |
---|---|---|---|
本质 | 客户端存储状态 | 服务器存储状态 | 客户端存储状态(自包含) |
是否需要Cookie | 是(直接或间接存储数据) | 是(存Session ID) | 可选(可存在Cookie或LocalStorage) |
是否无状态 | 否 | 否 | 是 |
安全性依赖 | 需要配合安全属性(HttpOnly、Secure) | Session ID安全性 | 签名防篡改 |
如果把状态维持比作“存放钥匙”:
- Cookie: 把钥匙和房间信息都给你(客户端全权负责)。
- Session: 把钥匙交给你(Session ID),房间信息放在服务器保管。
- Token: 把钥匙和房间信息做成一张防伪证书给你(Token里自带信息和签名)。
当然!下面我给你写Java 示例,演示三种场景:
五、示例
5.1 使用 Session 实现登录验证(Java 示例)
这是最常见的基于 Session 的登录流程:
流程概述:
- 用户提交用户名和密码。
- 服务器验证成功后,将用户信息写入 Session。
- 后续请求,通过 Session 判断是否登录。
示例代码(Servlet):
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
// 假设验证用户名和密码(此处仅示例)
if ("admin".equals(username) && "123456".equals(password)) {
// 获取 Session
HttpSession session = request.getSession();
// 存储登录标识
session.setAttribute("user", username);
response.getWriter().println("Login success");
} else {
response.getWriter().println("Invalid credentials");
}
}
}
访问受保护资源时:
@WebServlet("/profile")
public class ProfileServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession(false);
if (session != null && session.getAttribute("user") != null) {
String username = (String) session.getAttribute("user");
response.getWriter().println("Welcome, " + username);
} else {
response.getWriter().println("Please login first.");
}
}
}
5.2 使用 Cookie 实现“记住我”功能
场景:
用户勾选“记住我”,服务器写入一个长期有效的 Cookie,下一次访问时自动填充用户名。
示例代码:
@WebServlet("/login-cookie")
public class LoginCookieServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
String remember = request.getParameter("remember"); // "on"表示勾选
if ("admin".equals(username) && "123456".equals(password)) {
if ("on".equals(remember)) {
// 创建Cookie
Cookie cookie = new Cookie("rememberUser", username);
cookie.setMaxAge(7 * 24 * 60 * 60); // 7天
cookie.setPath("/");
response.addCookie(cookie);
}
response.getWriter().println("Login success with remember me");
} else {
response.getWriter().println("Invalid credentials");
}
}
}
后续访问时读取 Cookie:
@WebServlet("/home")
public class HomeServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = null;
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie c : cookies) {
if ("rememberUser".equals(c.getName())) {
username = c.getValue();
break;
}
}
}
if (username != null) {
response.getWriter().println("Welcome back, " + username);
} else {
response.getWriter().println("Hello, guest");
}
}
}
5.3 使用 JWT 实现无状态登录验证(示意流程)
要点:
- 登录成功后生成JWT。
- 客户端保存Token(通常放在前端LocalStorage)。
- 每次请求通过
Authorization
头携带Token。 - 服务端验证Token,无需Session。
⚠ Java中生产JWT通常用jjwt库(
io.jsonwebtoken:jjwt
)
依赖示例(Maven):
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
示例代码:
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.Claims;
@WebServlet("/login-jwt")
public class LoginJwtServlet extends HttpServlet {
private static final String SECRET_KEY = "mysecretkey123456";
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
if ("admin".equals(username) && "123456".equals(password)) {
// 生成JWT
String jwt = Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 60 * 60 * 1000)) // 1小时
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
response.getWriter().println("Token: " + jwt);
} else {
response.getWriter().println("Invalid credentials");
}
}
}
验证Token:
@WebServlet("/secure")
public class SecureServlet extends HttpServlet {
private static final String SECRET_KEY = "mysecretkey123456";
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7);
try {
Claims claims = Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
String username = claims.getSubject();
response.getWriter().println("Hello, " + username);
} catch (Exception e) {
response.getWriter().println("Invalid token");
}
} else {
response.getWriter().println("Authorization header missing");
}
}
}
六、安全性与最佳实践
6.1 HTTPS 的重要性
HTTPS(HTTP Secure) 是所有认证机制的基石:
防止中间人攻击(MITM)
- HTTP 明文传输时,攻击者可以窃取 Cookie、Session ID 或 Token。
- HTTPS 使用 SSL/TLS 加密数据传输,即使被拦截也无法解密。
数据完整性
- 防止请求或响应在传输过程中被篡改。
身份验证
- 确保客户端连接的是合法服务器(通过证书校验)。
实践建议:
- 所有登录、敏感数据传输都必须使用 HTTPS。
- 将 HTTP 自动重定向到 HTTPS。
6.2 如何防止 CSRF 与 XSS
CSRF(跨站请求伪造)
利用用户已登录状态,诱导用户在其他网站发起请求。
防御措施:
- 对敏感操作使用 CSRF Token(每个请求附带随机令牌)。
- 配置 SameSite=Strict Cookie,禁止第三方请求携带 Cookie。
- 对操作使用 双重验证(验证码/确认对话框)。
XSS(跨站脚本攻击)
攻击者将恶意脚本注入网页,被其他用户执行。
防御措施:
-
对所有用户输入进行转义或过滤。
-
输出 HTML 时使用安全模板或
escapeHtml()
。 -
设置 HTTP 响应头:
Content-Security-Policy: default-src 'self';
-
禁用不必要的 HTML 标签。
6.3 Token 失效与撤销机制
Token(如 JWT)天然是无状态的,签发后服务器不再记录,失效机制需要额外设计:
短过期时间
- Access Token 建议 15~30 分钟有效期。
Refresh Token
- 长期有效(如7天),只能用于换取新的 Access Token。
黑名单
- 服务端维护黑名单(撤销Token)。
- 典型场景:用户主动退出、敏感操作(改密码)后立即失效。
版本号或撤销标识
- Token中存储用户的token版本,数据库记录最新版本,旧token即失效。
示例:
token_version
列=3,JWT payload也有version=3,若不一致则判定失效。
6.4 Cookie 安全属性(HttpOnly、Secure、SameSite)
1.HttpOnly
防止 XSS 窃取 Cookie
- 设置后,JavaScript 无法通过
document.cookie
读取。
示例:
Set-Cookie: sessionid=abc123; HttpOnly
2.Secure
仅在 HTTPS 下传输
- 防止中间人攻击拦截。
示例:
Set-Cookie: sessionid=abc123; Secure
3.SameSite
防御 CSRF
- 控制 Cookie 在跨站请求中是否发送。
可选值:
- Strict:完全禁止跨站点发送 Cookie。
- Lax:部分允许(GET请求等)。
- None:允许跨站请求(需 Secure)。
示例:
Set-Cookie: sessionid=abc123; SameSite=Strict
当然!这是你最后一部分 总结 的简洁归纳:
七、总结
-
不同技术在现代 Web 的角色:
- Cookie: 最基本的客户端状态存储,适合保存用户偏好、简单信息,也用于携带 Session ID 或 Token。
- Session: 传统 Web 的核心状态管理方式,状态保存在服务器,依赖 Cookie 存 Session ID,安全性较高,适合单体应用。
- Token(尤其是 JWT): 现代无状态认证的主流方案,自包含用户信息,支持分布式、前后端分离、移动端、跨域和微服务架构。
-
如何根据业务场景选择合适方案:
- 中小型单体应用: 使用 Session + Cookie 实现登录态维护简单可靠。
- 前后端分离或移动端: 使用 Token(JWT)+ LocalStorage 或 HttpOnly Cookie 更灵活。
- 分布式/微服务: Token 无状态特性更适合横向扩展;若用 Session,需 Redis 等集中存储。
- 高安全要求: 无论使用哪种,务必结合 HTTPS、短有效期和防护机制(HttpOnly、SameSite、签名验证)。
-
身份验证技术的发展趋势:
- 从 纯 Cookie → Session + Cookie → Token(无状态),逐步向分布式、无状态、跨平台演进。
- OAuth2.0 和 JWT 已成为现代 API 和 SSO 的事实标准。
- 组合使用(如 HttpOnly Cookie 存 Token)越来越常见,用于兼顾安全与便利。
其他

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)