返回知识库

数据与服务 · 账号与安全

令牌Token

token 是服务器签名的一段字符串(header.payload.signature),客户端用 Authorization: Bearer 携带它发请求,服务器只验签名和 exp 就信任 claims——不查会话库,所以快、能跨服务,代价是过期前很难单条作废。

签发三段 token、带 Bearer 请求、验签不查库

无状态 token 不靠服务端记录,而靠一段服务器签名的字符串自证身份。先在这一台签发、请求、推进时间、刷新、篡改、撤销,亲眼看到签名和 exp 如何决定结果,再读后面的规则命名。

服务器用密钥对 header.payload 签名得到一段自洽的 token;客户端用Authorization: Bearer … 携带它发请求,服务器只验签名和 exp,不查会话库

访问令牌(access token)无令牌

(空)尚未签发;带 Bearer 请求会返回 401。

服务端时钟 T+0m
刷新令牌(refresh token)(空)长效 · 单独存储 · 服务端可撤销

撤销列表为空——这正说明无状态 token 默认没有「按一下就即时失效」的记录。

还没有发过带 Bearer 的请求;点「带 Bearer 请求」看服务器只验签名不查库的结果。

篡改 payload

原因 · 下一步 · 对照原因:服务端没有签发任何访问令牌,客户端也没有刷新令牌。下一步:点「签发访问令牌」,服务器会用密钥对 header.payload 签名,把 sub/role/exp 写进 payload。对照:签发后看「访问令牌」出现三段,刷新令牌单独存。

提示:主操作「签发访问令牌」是唯一的红色按钮;其余按 Tab 顺序可达。重点试三条对照——推进时间到 exp 过期再请求、打开「篡改 payload」再请求、加入黑名单后再请求。

签发台暴露的六条无状态规则

面板已经把每条规则演给你看了,这里把它们命名清楚,并补上无法直接操作的部分。

  • token = header.payload.signature 三段自洽字符串:header 写签名算法,payload 写 claims(sub / role / exp),signature 是服务端用密钥对 header.payload 算出的 HMAC。客户端只持有这段字符串,服务端不存它。
  • 服务器验签即信任 claims,不查会话库:每个请求带 Authorization: Bearer …,服务端重算签名与 token 自带的 signature 比对,再检查 exp——一致就信任 payload 里的身份,全程不读数据库或会话存储,所以快、能跨服务。
  • exp 是 payload 里的过期 claim:到点即过期,即便签名有效、浏览器手里的 token 看起来还完整也一样被拒;无状态 token 不做「空闲续期」,要新 exp 必须重新签发或刷新。
  • 签名防篡改,但不是加密:payload 只是 base64,任何人可读;把 role 改成 admin 会让签名对不上 → 401。需要保密时另行加密,那是 encryption 术语的范畴,不是 token 本身的职责。
  • 访问令牌短效 + 刷新令牌长效:access token 过期后,用 refresh token 向 /token 端点换新的;被盗风险窗口由 access 的短 exp 控制,refresh token 应单独安全存储且服务端可撤销。
  • 撤销靠短 exp + 黑名单,即时登出难:无状态 token 无法像 session 那样删一条记录就立即失效;要做「立刻踢下线」,只能维护一份 signature 黑名单(或短到极致的 exp),这正是它换「无存储」付出的代价。

什么时候用签名 token,什么时候换 session

从「谁来记状态、要不要跨服务、能不能即时撤销」出发,而不是默认都用 JWT。

  • 用签名 token:跨设备 / 跨服务复用凭据、不想要服务端会话存储、能接受「撤销靠短 exp + 黑名单」时——例如开放 API、微服务间传递身份、移动端登录。
  • 换服务端 session:Web 端登录态、需要随时主动撤销(踢人下线、登出立即生效)、记录可枚举与审计的场景。状态在服务端,撤销就是删一条记录——见 session 卡片。
  • 混用:浏览器同站请求用 Cookie + 服务端会话;开放 API 用 Authorization: Bearer … token。两套凭据各自管过期与撤销,承载层交给 cookie 判定。
  • 不要做的:把密码、敏感细节写进 payload(它是可读的 base64);在 URL 里带 token;用对称密钥签了还指望前端「验签」;登出只清客户端不维护黑名单。

从签发到刷新:签名 token 最短路径

只走这几步,每步都改变服务端可验证的状态或客户端手里的凭据。

  1. 登录验证通过后,服务端用密钥对 { alg, typ }base64 . { sub, role, exp }base64 计算 HMAC 作为 signature,拼成 header.payload.signature 返回;同时签发一个独立的 refresh token。
  2. 客户端把 token 存在合适的位置(同源 Web 用 HttpOnly Cookie,跨域 / 移动端用安全存储),每个请求带 Authorization: Bearer header.payload.signature,不在 URL 里传。
  3. 服务端每个请求重算签名比对、检查 exp;通过则从 payload 读身份,不查会话库;exp 到点一律 401,要求刷新或重新登录。
  4. access 过期后用 refresh token 换新 access;refresh 被盗 / 改密码 / 登出时,服务端撤销该 refresh;要「即时登出」则把尚未过期的 access signature 写进黑名单,等其短 exp 自然到期。

同一目标「token 被偷后立刻不可用」:靠短 exp + 黑名单,还是什么都不做

只改一处——偷到 token 后服务端怎么办——结果差很多。这是无状态 token 最该记住的一条。

正例:维护 signature 黑名单 + 用短 exp 访问令牌exp = now + 15m;黑名单 revoke(sig)

被偷的 access token 最多用到 exp(几分钟);发现异常时把 signature 写进黑名单,服务端验签后再查黑名单,命中即 401。即便不能像 session 那样瞬时全量失效,窗口也被压到很短。

反例:签了长效 token 又不维护撤销列表exp = now + 365d;无黑名单

access token 一旦泄漏,在长达一年的 exp 内服务端无从拒绝——因为「无状态」意味着服务端手里根本没有这条 token 的记录。等同于一把长期不换的钥匙,丢了也换不了锁。

快速自测

你的 access token 有效期 15 分钟、刷新令牌单独存储。攻击者偷到了 access token,但没偷到刷新令牌。15 分钟内你能做的最有效的「止损」是什么?

继续查证

术语的技术定义和行为以这些一手或权威资料为准。

下一步学

和本知识点经常一起出现的概念。