1、令牌基础:什么是访问令牌?为什么需要令牌?令牌与 Session 的区别
各位同学好,我是老赵。今天咱们开始聊访问令牌。
说实话,我在这个领域摸爬滚打了十几年,见过太多因为令牌管理不当引发的安全事故。有的公司直接把令牌明文存数据库,有的把过期时间设成十年,还有的干脆不用令牌——直接用用户名密码到处传。嗯,这些坑我都踩过。
所以第一节课,咱们先把基础打牢。什么是访问令牌?为什么我们需要它?它跟传统的 Session 到底有什么不同?
1.1 什么是访问令牌?
访问令牌,说白了就是一把「临时钥匙」。
你想想看,你去酒店办入住,前台给你一张房卡。这张房卡就是令牌。它上面写着你住哪个房间、住到什么时候。你拿着它,就能开门、用电梯、去健身房。但你退房之后,这张卡就失效了。
在计算机世界里,访问令牌也是一样的道理。它是一个字符串,通常是一串看起来乱码的字符,比如:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
这个字符串里,包含了谁发的令牌、给谁用的、什么时候过期、有什么权限等信息。客户端每次请求时带上它,服务端一看就知道:「哦,是你啊,请进。」
核心要点:访问令牌是客户端用来证明自己身份的凭证。它不依赖服务端保存状态,所有信息都编码在令牌本身里。
1.2 为什么需要令牌?
好,问题来了:为什么我们不能直接用用户名和密码?
我举个例子。你在手机上登录了淘宝,然后想用淘宝账号登录天猫、闲鱼、支付宝。如果每次都要输入密码,你烦不烦?而且密码在网络里传来传去,万一被截获了,你的账号就没了。
令牌解决了三个核心问题:
- 减少密码暴露——密码只用一次,后面都用令牌。就算令牌被偷了,改个密码就行,不用换账号。
- 细粒度权限控制——令牌可以只给部分权限。比如「只读权限」「仅限某个 API」「有效期 15 分钟」。我在项目中遇到过,有个同事把管理员令牌给了第三方服务,结果对方不小心删了整张表……从那以后,我坚持最小权限原则。
- 跨域/跨服务共享——令牌可以在不同系统间传递。你登录了 A 系统,拿着令牌就能访问 B 系统,只要它们信任同一个签发方。
我的建议:永远不要用密码做 API 鉴权。哪怕是你自己写的内部工具,也请生成一个临时令牌。我曾经见过一个团队,把数据库密码硬编码在移动端 App 里……嗯,后果很严重。
1.3 令牌与 Session 的区别
很多新手会问:「Session 也能做登录啊,为什么还要用令牌?」
这个问题问得好。咱们来对比一下:
| 对比维度 | Session | 访问令牌() |
|---|---|---|
| 存储位置 | 服务端内存/Redis | 客户端(浏览器、App) |
| 状态管理 | 有状态,服务端保存所有会话 | 无状态,服务端不保存 |
| 扩展性 | 差,需要 Session 同步或粘性会话 | 好,任意服务器都能验证 |
| 跨域支持 | 困难,Cookie 受同源策略限制 | 天然支持,放在请求头里即可 |
| 安全性 | 依赖 Cookie 安全属性 | 依赖令牌签名和传输加密 |
| 典型场景 | 传统单体 Web 应用 | 分布式系统、移动端、微服务 |
你看,Session 和令牌的核心区别在于「状态归谁管」。
Session 是服务端记着你。你每次请求,服务端去 Redis 里查一下:「哦,这个 Session ID 对应的是张三,他登录了,权限是管理员。」
令牌是客户端自己拿着证据。服务端收到令牌,验证一下签名,就知道:「嗯,这个令牌是合法的,里面写着张三,权限是管理员。」不需要去查数据库。
你想想看,如果你的系统只有一台服务器,用户也不多,用 Session 完全没问题。但如果你有 100 台服务器,用户遍布全球,Session 同步就成了噩梦。而令牌天生就是为分布式设计的。
注意:令牌无状态不代表它不需要管理。恰恰相反,令牌的生命周期管理比 Session 更复杂。你没法主动让一个令牌失效(除非用黑名单),所以过期时间、刷新机制、撤销策略都变得非常重要。后面几章我会详细讲。
1.4 令牌的核心组成
咱们来看看一个典型的访问令牌长什么样。以最流行的 JWT(JSON Web )为例:
// Header(头部)
{
"alg": "HS256", // 签名算法
"typ": "JWT" // 令牌类型
}
// Payload(载荷)
{
"sub": "user_12345", // 主体(用户 ID)
"iss": "auth.example.com", // 签发者
"iat": 1700000000, // 签发时间
"exp": 1700003600, // 过期时间
"scope": "read write" // 权限范围
}
// Signature(签名)
// 对 Header + Payload 用密钥签名,防止篡改
这三部分用点号拼接,就成了前面那串乱码。客户端拿到后,每次请求放在 Authorization: Bearer <> 头里。
我个人习惯把令牌比作「数字身份证」。身份证上有你的照片、姓名、有效期,还有公安部门的防伪印章。令牌也一样,有用户信息、有效期、签发方签名。伪造身份证很难,伪造令牌也很难——除非密钥泄露。
1.5 一张图看懂令牌体系
下面这张图展示了令牌在整个系统中的位置和流转过程:
这张图展示了令牌从签发到撤销的完整路径。你会发现,令牌不是「发出去就不管了」。它需要安全传输、正确验证、及时刷新,必要时还得能撤销。每一个环节都可能出问题。
1.6 什么时候该用令牌?
说了这么多,咱们总结一下适用场景:
- 微服务架构——服务间调用,令牌比 Session 方便得多
- 移动端 App——没有 Cookie 机制,令牌是标准方案
- 单点登录(SSO)——一个令牌访问多个系统
- 第三方 API——给合作伙伴发令牌,而不是共享密码
- 前后端分离——前端 SPA 用令牌调用后端 API
反过来,如果你的项目是传统的单体应用,用户量不大,也不涉及跨域,用 Session 反而更简单。别为了用令牌而用令牌。
我的经验:选技术方案时,先想清楚你的系统未来三年会变成什么样。我见过太多项目,一开始图省事用 Session,后来要加移动端、要拆分微服务,结果全得重写。令牌虽然初期配置麻烦点,但扩展性好得多。
1.7 小结
好,第一节课就到这里。咱们讲了三个核心问题:
- 访问令牌是一把临时钥匙,用来证明你的身份和权限
- 它解决了密码暴露、权限控制、跨域共享三大痛点
- 跟 Session 比,令牌是无状态的,更适合分布式系统