JWT 到底装了什么?拆开看看
现在做接口鉴权,JWT 出场率很高。但很多人对它的理解停在"一个字符串,带上就能证明身份",至于里面装了什么、为什么这么设计,一知半解。
这篇就把 JWT 拆开看。搞懂它的结构,很多用错的地方自然就避开了。
三段,各司其职
JWT 长这样:
eyJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjEyMywiZXhwIjoxNzAwMDAwMDAwfQ.xxxxxx用点号隔开,正好三段。
第一段是头部,说明这个 token 用什么算法签的名。第二段是负载,装着真正的数据。第三段是签名,用来防止内容被人偷偷改掉。
前两段是 Base64 编码的 JSON,解出来能看:
// header{"alg":"HS256","typ":"JWT"}// payload{"uid":123,"exp":1700000000}最容易搞错的一点:它不是加密
这是新手最常踩的坑。
不少人以为 payload 是加密的,别人看不到,于是把手机号、身份证这类信息塞进去。这就出大事了。
Base64 只是编码,不是加密。任何人拿到这个 token,把中间一段解一下,内容一目了然。JWT 能防的是"被篡改",防不了"被偷看"。
所以记住一条底线:payload 里只放不敏感的数据,比如用户 id、角色、过期时间。真正敏感的东西,放在服务端查。
签名在防什么
那签名是干嘛的?它防的是篡改。
服务器用密钥对"头部 + 负载"算出一个签名,附在后面。下次你带着 token 来,服务器重新算一遍,和你的签名对比。一样,说明内容没被动过;不一样,说明有人改了 payload 想冒充别人。
所以密钥千万不能泄露。密钥一漏,别人就能伪造任意 token,整个鉴权体系就崩了。
什么时候会用到 RS256
签名算法常见两种。HS256 是对称的,加密解密用同一个密钥。RS256 是非对称的,私钥签名、公钥验签。
单体服务里,HS256 就够用。但如果多个服务要独立验证 token,用 RS256 更合适——发 token 的服务拿私钥,其他服务只拿公钥,这样公钥即使泄露,别人也伪造不了。验证和签发分开,是 RS256 最大的好处。
payload 里常见的几个字段
除了你自己塞的,JWT 标准还定义了几个约定字段,用不用看场景。
exp是过期时间,这个几乎必填,不设过期等于发了个永久凭证。nbf是"在此之前无效",iat是签发时间。iss和aud分别标识签发方和接收方,多系统之间用它防错拿。
{"uid":123,"role":"user","exp":1700000000,"iat":1699996400}无状态的好处,和它带来的麻烦
JWT 最大的卖点是无状态。服务器不存任何东西,拿到 token 验个签就知道你是谁,天然适合横向扩展。
但这份"不存东西",也带来一个麻烦:想主动作废,很难。
用户改了密码、管理员要强制下线,传统 Session 删一条记录就行。JWT 呢?服务器没存,删无可删。只能靠缩短有效期,或者额外维护一个黑名单,把无状态的好处又打了折扣。
所以别把 JWT 当成万能药。要能随时踢人的场景,Session 反而更合适。
几个值得注意的细节
有效期别设太长。有人图省事,access token 一设就是一年,等于把凭证长期暴露在外。正常做法是短有效期加 refresh 机制。
时钟偏差要注意。exp依赖服务器时间,如果签发方和验证方的机器时间差太多,可能出现"刚签发就过期"的怪事。留个几分钟的宽容窗口可以缓解。
别在 payload 里塞一堆东西。token 每次请求都要带上,塞得越满,请求头越大,纯属给自己找麻烦。
小结
JWT 不神秘,拆开就三段:头、负载、签名。它擅长的是让验证变得无状态、好扩展,代价是难以主动作废。
搞清楚它防什么、不防什么,你就能判断什么时候该用它,什么时候该老老实实回到 Session。
如果这篇对你有帮助,点个赞再走。评论区聊聊你在鉴权上踩过的坑,我挑典型的再写一篇。