--- title: "03-JWT验证" created: 2025-12-02 tags: - 项目 aliases: - JWT验证 --- # JWT验证 ## Session ### 传统 Session 验证方式 在传统的 Session 验证模式中,用户登录成功后,服务器会创建一个会话(Session),并生成一个唯一的 `SessionID`。这个 `SessionID` 类似于一个“身份证号”,会被保存在客户端的 Cookie 中。之后,每次用户请求授权页面时,浏览器会自动将这个 `SessionID` 发送到服务器。服务器会根据这个 ID 查询并验证对应的用户信息。 ### **传统 Session 模式的问题:** 1. **存储压力大**:服务器需要维护大量的会话数据,当用户量很大时,会对服务器的存储资源产生压力。 2. **跨域复杂**:SessionID 通常依赖于 Cookie,而 Cookie 的跨域传输有严格的安全策略,这给分布式和跨域场景的应用增加了复杂性。 ## JWT ### JWT(JSON Web Token)的原理 JWT 解决了传统 Session 跨域验证的困难,并减少了服务器的存储压力。 它的原理是通过生成一个自包含的 Token(令牌),其中包含了用户的基本信息,并通过数字签名来保证 Token 的完整性和不可篡改性。与传统 Session 不同,JWT 是无状态的,不需要服务器存储会话信息。 #### JWT 的组成 JWT 由三部分组成,分别为 Header(头部)、Payload(载荷)、Signature(签名)。这三部分通过 `.` 连接起来形成一个完整的 JWT 字符串。 - **Header**:头部一般会声明使用的签名算法,比如 `HMAC-SHA256`。 - **Payload**:载荷部分包含用户的基本信息和一些声明(Claims)。这部分内容是明文的,因此不应包含敏感信息。常见的 Claims 有: - `sub`(subject):用户 ID - `exp`(expiration time):过期时间 - `iat`(issued at):签发时间 - `iss`(issuer):签发者 - **Signature**:签名部分是对前两部分数据进行加密的结果,用来验证数据的完整性。签名使用的密钥(Secret)是服务器端保存的,不会暴露给客户端。 #### JWT 生成流程 1. **用户登录**:用户在登录页面输入用户名和密码,服务器会验证这些凭证是否正确。 2. **生成 Token**:服务器验证成功后,会根据用户信息生成一个 JWT。具体步骤如下: - 将用户信息(如 user-id)和一些声明信息(如过期时间、签发者)放入 `Payload` 部分。 - 头部(Header)声明签名算法(如 `HMAC-SHA256`)。 - 使用服务器的密钥(Secret)通过声明的算法对头部和载荷进行加密,生成签名部分。 - 最后将这三部分拼接成一个 JWT 字符串,并返回给客户端。 例如,生成的 JWT 字符串可能如下: ```text eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvbiBEb2UiLCJpYXQiOjE1MTYyMzkwMjJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c ``` 这个字符串包含了三部分:头部(第一段)、载荷(第二段)和签名(第三段)。 #### JWT 的验证过程 当用户需要访问授权页面时,客户端会将 JWT 附带在请求的 `Authorization` 头中发送到服务器,形式类似: ```text Authorization: Bearer ``` 服务器在接收到请求后,会按照以下步骤验证 Token: 1. **解析 Token**:将收到的 JWT 字符串解码,分为 `Header`、`Payload` 和 `Signature` 三部分。 2. **验证签名**:服务器根据 `Header` 中声明的加密算法和预先保存的密钥,重新对 `Header` 和 `Payload` 进行加密,生成新的签名。 3. **签名比对**:将生成的签名与 Token 中的签名进行比对。如果一致,则说明 Token 没有被篡改,并且验证通过。 4. **检查过期时间**:验证通过后,还需要检查 `exp` 声明(过期时间),如果当前时间超过了这个时间,则 Token 失效。 ### Access-Token 和 Refresh-Token 为了提高安全性和灵活性,JWT 通常会引入 `Access-Token` 和 `Refresh-Token`: #### **Access-Token(访问令牌)**: - **主要作用**:`Access-Token` 是用来验证用户身份的令牌。它包含了用户的基本信息和权限,通常具有较短的有效期(如 5 分钟到 30 分钟)。服务器在验证请求时,会使用这个 `Access-Token` 来确认用户的身份。 - **特点**:因为 `Access-Token` 的有效期较短,即使它被窃取,攻击者可以利用的时间也有限。它在短时间内反复使用时更加安全和高效。 #### **Refresh-Token(刷新令牌)**: - **主要作用**:`Refresh-Token` 主要用于获取新的 `Access-Token`。它在用户登录时由服务器一并签发,并且具有较长的有效期(可能是几小时、几天,甚至更长)。 - **特点**:`Refresh-Token` 通常不会像 `Access-Token` 那样频繁传递,它只在 `Access-Token` 过期时才使用,用于向服务器请求新的 `Access-Token`。`Refresh-Token` 的生成和签发更加严格,可以设置为仅在特定 IP 地址或设备上有效。 #### 双 Token 机制及其安全性 ##### **Token 轮换机制**: JWT 通常采用 `Access-Token` 和 `Refresh-Token` 的双 Token 机制来降低用户端 Token 被窃取后的风险。它的具体工作流程如下: 1. **用户登录**:用户通过用户名和密码登录,服务器验证成功后,会签发一个短期有效的 `Access-Token` 和一个长期有效的 `Refresh-Token`。这两个令牌会同时返回给用户,用户需要安全地存储它们。 2. **访问受保护资源**:在访问受保护的资源时,用户每次请求都会携带 `Access-Token`,服务器验证 `Access-Token` 是否有效。如果有效,则允许访问。 3. `Access-Token` **过期**:由于 `Access-Token` 的有效期较短,当它过期后,用户的请求将被服务器拒绝(返回 401 未授权状态)。 4. **使用** `Refresh-Token` **获取新的** `Access-Token`:用户在 `Access-Token` 过期后,可以使用 `Refresh-Token` 向服务器发送请求,服务器会验证 `Refresh-Token` 是否有效。如果验证成功,服务器将生成一个新的 `Access-Token` 并返回给用户。 5. **更新** `Refresh-Token`:为进一步提升安全性,可以在生成新 `Access-Token` 时,更新 `Refresh-Token`,以防止 `Refresh-Token` 长期被窃取带来的风险。 ##### **防止 Token 窃取的措施**: 1. **缩短** `Access-Token` **的有效期**:通过将 `Access-Token` 的有效期设定得较短,即使 Token 被窃取,攻击者也只能在有限时间内进行操作。 2. **限制** `Refresh-Token` **的使用**:`Refresh-Token` 可以设置为只能在特定的 IP、设备或时间段内使用,防止跨设备的非法使用。 3. **Token 黑名单机制**:服务器可以维护一个 Token 黑名单,当用户主动注销或检测到异常行为时,可以将相关的 `Refresh-Token` 列入黑名单,拒绝所有使用该 Token 的请求。 4. **HTTPS 传输**:确保所有 Token 的传输过程都在安全的 HTTPS 通道中,避免中间人攻击。 5. **安全存储**:客户端需要妥善存储 `Access-Token` 和 `Refresh-Token`,避免在不安全的环境中暴露。 ### JWT 及双 Token 机制的优势与适用场景 #### JWT 的优缺点 **优点:** - **无状态**:JWT 不需要服务器存储会话数据,验证过程完全基于 Token 自身,减轻了服务器的存储负担。 - **跨域便利**:因为 JWT 仅需要附带在请求头中,不依赖 Cookie 的跨域机制,特别适合前后端分离的应用场景。 - **安全性**:通过数字签名保证了 Token 的完整性,如果 Token 被篡改,验证签名时就会失败。 **缺点:** - **Payload 明文存储**:JWT 的载荷部分是明文存储的,任何人都可以解码查看其中的内容,因此不要将敏感信息放入 `Payload`。 - **Token 长度较大**:与 SessionID 相比,JWT 的字符串较长,占用更多的带宽。 - **无法主动失效**:一旦 Token 发放出去,就无法在不修改密钥的情况下主动使其失效(除非通过 Redis 等方式进行 Token 黑名单控制)。 **使用场景:** - **单点登录(SSO)**:因为 JWT 可以在多个服务器之间共享,适用于多服务或多应用的统一身份验证。 - **移动应用**:JWT 不依赖浏览器的 Cookie,适合移动端使用。 - **微服务架构**:每个微服务都可以验证 JWT,不需要单独的认证中心。 JWT 是一种无状态的、基于令牌的验证方式,适用于分布式架构、微服务和跨域应用场景。相比传统的 Session 验证方式,JWT 提高了跨域访问的便利性,并减少了服务器的存储压力。尽管有安全性和失效管理方面的不足,但通过合理的设计和使用,它依然是现代 Web 应用中广泛采用的认证方案之一。 #### 双 Token 机制优势: - **减少频繁的身份验证**:用户在短期内无需反复登录,提高了用户体验。 - **增强安全性**:即使 `Access-Token` 被窃取,攻击者的有效时间也很短;而 `Refresh-Token` 的使用相对较少,可以通过更严格的限制来进一步保护。 - **提高灵活性**:`Refresh-Token` 的长效性允许服务器根据需要自动延长用户的会话,而无需用户重新登录。 总结来说,`Access-Token` 用于频繁的身份验证,而 `Refresh-Token` 则用于在 `Access-Token` 过期时获取新的令牌。通过双 Token 机制,可以降低 Token 被窃取带来的风险,并提供更加灵活和安全的验证方式。 --- **项目分区导航**: [[02-Postman|Postman]] ⬅️ | 03-JWT验证 | ➡️ [[04-前端请求工具(HTTP请求库)|前端请求工具(HTTP请求库)]]