JWT

先给你一句总纲,先稳住:

✅ HS256:对称签名;RS256:非对称(RSA)签名,你这句是对的!
⚠️ 注意:不管 HS256 / RS256,Header 和 Payload 永远只是 Base64URL 编码,不是加密!编码方式【写死是Base64URL】,Header里面只写【签名算法】,不写编码方式!

编码 = 换一种写法,随时还原,人人看得懂;加密 = 糊成乱码,要有密钥才能解开。
JWT 全程固定编码:Base64URL(是Base64的一个变种,把 + / = 改掉,适合放URL、请求头里面)


一、先拆分【生成JWT全过程】,一步一步(分 HS256 举例,再对比RS256)

JWT结构:【header串】.【payload串】.【signature签名串】

第1步:写 Header(JSON)

{
  "alg": "HS256",
  "typ": "JWT"
}
  • alg:签名算法!这里写 HS256 或者 RS256
  • typ:固定写JWT,代表这是JWT
    👉 然后:把这个JSON,做 Base64URL编码 → 得到第一段字符串

第2步:写 Payload(JSON,存业务信息)

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

👉 同样:这个JSON,直接 Base64URL编码 → 第二段字符串

❗重点:这里没有加密!就是单纯转成Base64URL,随便谁拿到,都可以还原出这个JSON!Header里不会写Base64,这个编码是JWT协议规定死的。

第3步:算签名(最容易迷糊的地方来了!)

把前面两段拼起来:base64Header.base64Payload
然后根据Header里写的alg,走不同签名逻辑:

✅ 如果 alg = HS256(对称签名,HMAC-SHA256)

公式:
签名 = HMAC-SHA256( "第一段.第二段", 同一个Secret密钥 )

  • HMAC 是什么:拿【拼接字符串 + 共享密钥】丢进SHA256算出一个指纹(带锁的指纹)
  • 这个Secret,后端存好,前端不能拿到这个Secret!前端只存完整JWT字符串!
    算完这个结果,再转Base64URL,就是第三段签名。

✅ 如果 alg = RS256(非对称签名,RSA-SHA256)

公式:
签名 = RSA私钥签名( SHA256("第一段.第二段") , 私钥 )
流程拆开:

  1. 先对 第一段.第二段 算 SHA256 摘要(普通指纹)
  2. 用服务器自己的RSA私钥,对这个指纹签名盖章

私钥:只有服务器自己攥着,绝不外传;配套公钥可以公开出去给其他服务验签

👉 最后三段用.拼起来,就是一长串JWT,发给前端。前端存起来(localStorage/cookie)

📌 一句话区分两个签名:
HS256:一把共享密码secret,算签名、验签名都用这同一个密码
RS256:一对密钥,私钥用来生成签名,公钥只用来验签名


二、后端收到前端带过来的JWT之后:验证流程!

前端每次请求,把整串JWT放在请求头带过来。后端拿到 A.B.C

  1. 先按.切成三块:A(编码后的header)、B(编码后的payload)、C(签名串)
  2. 把A做Base64URL解码 → 拿到Header JSON,读出里面 alg,看是HS256还是RS256
  3. 重新计算一遍预期签名:
    • 如果是HS256:拿 A.B + 后端本地保存的Secret,重新跑一遍HMAC-SHA256,算出【新签名】
    • 如果是RS256:拿 A.B 先算SHA256摘要,拿公钥去校验C这个签名是不是这个摘要盖出来的
  4. 对比校验:
    • HS256:新算出来的签名 和 传过来的C 一模一样 ✅ 校验通过
    • RS256:公钥校验签名合法 ✅ 校验通过
  5. 校验成功之后:才把B做Base64URL解码,拿到Payload里面用户信息,鉴权放行

⚠️ 关键点:校验签名,是先校验,再解码拿payload!
如果你自己改了payload里面的name、admin=true,B就变了,A.B跟着变,后端重新算签名就对不上,直接拒绝。


三、把你刚才一堆疑问单独拎出来逐个回答

  1. Q:Payload里面是编码?是Base64吗?
    A:是,Base64URL(Base64变体),协议固定,Header里不写这个编码方式。Header只写签名算法(HS256/RS256)
  2. Q:Header里面写的是加密算法?
    A:❌ 准确说:签名算法!JWT这里没有加密业务数据,只有签名。HS256叫对称签名算法,不是加密算法。
  3. Q:签名那边是把Header和Payload拼起来算东西?
    A:✅ 对,把编码后的第一段、第二段,中间加个点拼在一起,再根据alg的算法算出签名,作为第三段
  4. Q:前端拿到之后做什么?
    A:前端啥都不用算!只负责存、每次请求带上这整串字符串,不参与签名、验签! secret/私钥前端拿不到!

四、极简对比 HS256 vs RS256

项目 HS256(HMAC-SHA256) RS256(RSA-SHA256)
类型 对称签名 非对称签名
密钥 同一个Secret,签名验签都用它 私钥签名,公钥验签(一对)
适合场景 单体项目,就这一个服务发token、验token 微服务、第三方登录,多个服务验签,公钥分发

五、一个超级容易踩的坑再强调

很多人混淆:
Base64URL = 编码(JWT Header、Payload用这个)
SHA256 = 哈希摘要(算指纹)
HMAC-SHA256(HS256) = 对称签名
RSA-SHA256(RS256) = 非对称签名

===== 签发 JWT =====
# a 是编码后的Header.编码后的Payload
a = base64URL(Header) + "." + base64URL(Payload)

if alg == HS256:
    sign_raw = HMAC-SHA256(a, secret)
    sign = base64URL(sign_raw)
elif alg == RS256:
    digest = SHA256(a)
    sign_raw = RSA_SIGN(digest, RSA_pri)
    sign = base64URL(sign_raw)

token = a + "." + sign   # 也就是 A.B.C,发给前端

===== 校验 JWT =====
A,B,C = token.split(".")
a = A + "." + B

if alg == HS256:
    expected_raw = HMAC-SHA256(a, secret)
    expected_C = base64URL(expected_raw)
    if expected_C == C: ✅通过
    else: ❌失败

elif alg == RS256:
    digest = SHA256(a)
    # ==========这里是唯一要改的地方!==========
    sign_raw = base64URL_decode(C)
    ok = RSA_VERIFY(digest, sign_raw, RSA_pub)
    if ok == true: ✅通过
    else: ❌失败
posted @ 2026-10-22 11:22  十三山入秋  阅读(13)  评论(0)    收藏  举报