JWT 是什么:三段式结构、签名验证与调试排查

登录后的接口请求头里带着一长串 eyJhbGciOi... 开头的令牌,两个点把它分成三段——这就是 JWT(JSON Web Token)。它为什么能证明「你是你」?改一个字为什么会立刻失效?这篇拆开看。

一、三段结构:头部、载荷、签名

段内容作用
第一段 Header{"alg":"HS256","typ":"JWT"} 的 Base64URL声明签名算法
第二段 Payload{"sub":"1001","exp":1770000000,...} 的 Base64URL存放用户信息与过期时间
第三段 Signature对前两段的 HMAC/RSA 签名防篡改的核心

关键认知:前两段只是 Base64URL 编码,不是加密,任何人粘贴到解码工具里都能读到内容。所以 payload 里只能放不敏感的字段(用户 ID、角色、过期时间),绝不能放手机号、身份证。签名才是安全所在:服务端用只有自己知道的密钥对前两段计算签名,改了 payload 中任何一个字符,验签都会失败。

二、exp 字段:过期判断就藏在这里

payload 里的 exp 是 Unix 时间戳(秒),服务端每次收到令牌都会比较它和当前时间。排查「为什么我登着登着就掉了」,先解码看 exp——常见坑有两种:一是令牌有效期本来就很短(如 2 小时),需要用刷新令牌机制续期;二是服务器时钟与标准时间偏差过大,导致刚签发的令牌「一出生就过期」。

三、常见 401 报错的排查顺序

  1. 先本地解码:确认 payload 里的 exp 是否真的过了、用户字段是否符合预期——一半以上的问题在这一步就水落石出;
  2. 查传输完整性:请求头里 Authorization: Bearer <token>,Bearer 后有一个空格;令牌被网关截断或前后带了引号都会导致解析失败;
  3. 查算法一致性:服务端期望 HS256 而签发用了 RS256(或反过来),验签必然失败。多服务架构里这是高频坑;
  4. 查密钥轮换:如果用了 RS256 + JWKS,密钥轮换期间旧令牌可能验不过,等缓存刷新或重新登录获取新令牌。

四、本地调试的三种方式

  1. 浏览器 DevTools:Network 面板选中请求 → Headers 里找到 Authorization 头,复制令牌。顺手确认请求确实带上了令牌——很多「接口 401」其实是拦截器没把令牌塞进请求头;
  2. 命令行一行解码:把令牌第二段取出来做 Base64URL 解码,echo ' eyJwYXlsb2Fk...' | base64 -d 2>/dev/null(macOS 用 base64 -D),秒出 payload JSON;
  3. 解析工具:粘贴整串直接看三段内容和 exp 状态,省去手动分段。注意:调试用的一定是测试环境的令牌;生产令牌哪怕只解码也应视为敏感信息,不要贴进任何第三方网站——虽然解码不需要密钥,但令牌本身在有效期内就是通行证。

养成习惯:令牌只出现在环境变量和内存里,不进代码仓库、不进聊天记录。解完密钥相关的疑点后,到服务端把该测试用户的会话作废一次,确认旧令牌确实失效,才算排查闭环。

🔓 JWT 解析器:粘贴令牌立即解码三段内容,exp 过期时间自动换算成人类时间并标红过期状态。只解码不发送,本地完成。

常见问题

问:JWT 和 Session 有什么区别?
Session 状态存在服务端,JWT 把状态放在令牌里由客户端携带。JWT 的代价是「签发后无法主动作废」,所以高安全系统会配合黑名单或短有效期 + 刷新令牌。

问:Base64URL 和普通 Base64 有什么不同?
把 + 换成 -、/ 换成 _ 并去掉结尾的 =,避免在 URL 和 Header 里被转义破坏。