JWT鉴权的流程和原理


好的,我们来详细、清晰地介绍一下JWT(JSON Web Token)的鉴权流程和其背后的原理。这是一个在现代Web应用和API安全中非常核心的概念。

我将用一个通俗的比喻来帮助你理解:

  • 传统的Session认证:就像你去一个游乐场,在入口处把你的随身物品(用户信息)存放在一个储物柜里(服务器Session存储),然后游乐场给你一个手环/储物牌(Session ID)。之后你玩任何项目,都需要出示这个手环,工作人员(服务器)看到手环后,会去储物柜区域找到你的柜子,确认你的信息。特点是服务器需要维护大量的储物柜
  • JWT认证:就像你拿到了一张带有防伪签名的“贵宾通行证”。这张通行证本身就写清楚了你的信息(你是谁、有什么权限、有效期到何时),并且上面有主办方(服务器)的特殊防伪签名。你玩任何项目,只需出示这张通行证,工作人员一看,确认签名是真的,信息没被篡改,就直接让你通过。特点是工作人员(服务器)无需再去查阅档案或储物柜

1. JWT的原理:它是什么构成的?

JWT的本质是一个经过签名的、自包含的字符串。它由三部分组成,每个部分都使用Base64Url编码,并用点(.)连接起来。

xxxxx.yyyyy.zzzzz
(Header . Payload . Signature)

a) 第一部分:Header (头部)

Header部分是一个JSON对象,通常包含两部分信息:

  • typ (Type): 令牌的类型,固定为 “JWT”。
  • alg (Algorithm): 使用的签名算法,例如 HS256 (HMAC SHA256) 或 RS256 (RSA)。

示例JSON:

{
  "alg": "HS256",
  "typ": "JWT"
}

这部分JSON会经过Base64Url编码,形成JWT的第一部分。

b) 第二部分:Payload (载荷)

Payload部分也是一个JSON对象,这里存放了所有需要传递的实际数据,这些数据被称为“声明 (Claims)”。声明分为三类:

  • Registered Claims (标准中注册的声明):这些是官方建议使用的预定义声明,以提供一组通用的、可互操作的声明。例如:
    • iss (Issuer): 签发者
    • sub (Subject): 主题(通常是用户的ID)
    • aud (Audience): 接收者
    • exp (Expiration Time): 过期时间戳。这是非常重要的一个声明,用于保证令牌在一定时间后失效。
    • iat (Issued At): 签发时间戳
  • Public Claims (公共的声明):可以由使用者自由定义,但为了避免冲突,应该在IANA JSON Web Token Registry中注册。
  • Private Claims (私有的声明):这是我们最常使用的,由通信双方自由定义的声明。例如,你可以放入用户的ID、角色、用户名等自定义信息。

示例JSON:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true,
  "exp": 1719768799
}

这部分JSON也会经过Base64Url编码,形成JWT的第二部分。

⚠️ 重要提醒:Payload部分仅仅是经过了Base64Url编码,它没有被加密! 这意味着任何人都可以解码并读取其中的内容。因此,绝对不要在Payload中存放任何敏感信息,如密码。

c) 第三部分:Signature (签名)

Signature是JWT最核心的安全保障。它的生成过程如下:

  1. 将经过Base64Url编码的Header和Payload用点(.)连接起来,形成一个字符串。
  2. 使用在Header中定义的签名算法(如HS256),配合一个只有服务器知道的密钥(secret),对这个字符串进行加密签名。

伪代码示例:

Signature = HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  your_secret_key
)

签名的作用:

  1. 验证身份:确保令牌是由可信任的服务器签发的(因为只有服务器知道密钥)。
  2. 防止篡改:如果有人试图修改Header或Payload的内容,由于他们没有密钥,无法生成正确的签名。服务器在验证时会发现签名不匹配,从而拒绝该令牌。

2. JWT的鉴权流程

下面是JWT在实际应用中的完整流程:

  1. 用户登录:用户使用用户名和密码发起登录请求。

  2. 服务器验证与签发Token

    • 服务器接收到请求,验证用户名和密码是否正确。
    • 验证通过后,服务器根据用户ID、角色等信息,结合过期时间等,生成Payload。
    • 服务器使用保存在服务端的密钥(secret),对Header和Payload进行签名,生成一个完整的JWT。
  3. 服务器返回Token:服务器将生成的JWT字符串作为响应返回给客户端。

  4. 客户端存储Token

    • 客户端(通常是浏览器或App)在收到JWT后,需要将其存储起来。
    • 常见存储位置包括:浏览器的 localStoragesessionStorageHttpOnly Cookie
  5. 客户端携带Token发起请求

    • 此后,客户端向服务器发起的每一个需要鉴权的API请求,都必须在HTTP请求头中携带这个JWT。
    • 最规范的方式是放在 Authorization 请求头中,并使用 Bearer 方案:
      Authorization: Bearer <your_jwt_token>
      
  6. 服务器验证Token

    • 服务器的API端点在收到请求后,会有一个**中间件(Middleware)**来专门处理鉴权。
    • 中间件会从 Authorization 请求头中提取JWT。
    • 服务器不需要查询数据库,而是执行以下验证步骤:
      a. 验证签名:服务器取出请求中的Header和Payload,用自己存储的同一个密钥(secret),按照同样的算法重新计算一次签名。然后,将计算出的新签名与JWT中自带的签名进行比对。
      * 如果一致,说明令牌有效且未被篡改。
      * 如果不一致,说明令牌是伪造的或被篡改过,认证失败。
      b. 验证声明:签名验证通过后,服务器还会检查Payload中的声明,例如,检查 exp 声明,确认令牌是否已经过期。
    • 所有验证都通过后,服务器就认为该请求是合法的,可以信任Payload中的用户信息(如用户ID),并继续处理该请求。如果验证失败,则返回401 Unauthorized错误。

3. JWT的优缺点

优点:
  • 无状态与可扩展性:服务器端无需存储任何Session信息。这使得服务器可以轻松地水平扩展(增加更多服务器实例),而不用担心Session同步问题。非常适合微服务架构。
  • 自包含:令牌本身包含了所有需要的信息,可以减少因查询用户信息而对数据库造成的压力。
  • 跨域友好:可以轻松地用于跨域的API调用,因为JWT是通过HTTP头发送的,不受浏览器同源策略的限制。
  • 多端适用:非常适合Web、移动App、桌面应用等多种客户端。
缺点:
  • 无法主动失效:一旦一个JWT被签发,在它到期之前,它就一直是有效的。如果用户在此期间想要“注销登录”,服务器无法主动让这个令牌失效。常见的解决方案是:
    • 设置较短的过期时间,并配合“刷新令牌(Refresh Token)”机制。
    • 维护一个“黑名单”,将需要失效的令牌ID存入Redis等缓存中。每次验证时先查黑名单。但这又让服务变得“有状态”了,违背了JWT的初衷。
  • 体积较大:相比于一个简单的Session ID,JWT的体积要大得多,会增加每次HTTP请求的开销。
  • 安全性:签名的密钥必须被妥善保管,一旦泄露,攻击者就可以签发任意的、合法的令牌。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hwg985

祝老板生意兴隆,财源广进

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值