JWT 技术(JSON Web Token) 全解:原理、应用与生产级避坑指南

笔者阅读很多 JWT 技术的博文,发现大多只是讲 “JWT 是什么”,而这篇文章重点介绍它为什么出现、结构细节、以及生产环境中最棘手的“注销与续签”问题。

在前后端分离、微服务架构大行其道的今天,JWT(JSON Web Token)几乎成为了身份认证的代名词。

很多开发者只知道它是一个“长长的字符串”,用来做登录校验,但并不清楚它内部的运作机制,以及它在安全性上的潜在风险。本文将从原理、结构、流程、以及最核心的生产陷阱四个维度进行详细拆解。

一、为什么需要 JWT?(Session vs Token)

在 JWT 出现之前,我们主要使用 Session + Cookie 的方式。

1.传统Session的认证痛点

  • 服务端有状态:服务端需要保存 Session 数据(内存或Redis)。
  • 扩展性差:集群环境下,必须做 Session 共享(如存入Redis),否则用户请求落到不同服务器会掉线。
  • 移动端支持差:原生 App 对 Cookie 的支持不如浏览器友好。
  • CSRF 风险:基于 Cookie 自动发送的特性,容易遭受跨站请求伪造攻击。

2.JWT(JSON Web Token)认证优势

  • 服务端无状态:服务器不保存任何会话数据,Token本身包含了用户信息和有效期。
  • 扩展性强:服务器拿到 Token 只要“解密/验签”即可,天然支持分布式、微服务。
  • 跨语言/跨端:JSON是通用的,且不依赖 Cookie ,适合 App、小程序、IoT 设备

一句话总结

Session 是把“通行证”存在服务器,给你个号码;JWT 是把“通行证”直接印发给你,服务器只负责查验真伪。

二、JWT 的结构解剖

一个标准的 JWT 字符串看起来是这样的:

xxxxx.yyyyy.zzzzz

它由 3 部分 组成,中间用 . 分隔:

1. Header(头部)

描述 Token 的元数据,通常包含两部分:

{ "alg": "HS256", // 签名算法,如 HMAC SHA256 或 RSA "typ": "JWT" // 令牌类型 } 

Base64Url 编码后,构成第一部分。

2. Payload(负载)

这是最核心的部分,存放有效信息(Claims)。包含标准字段和自定义字段:

{ "sub": "1234567890", // 用户ID "name": "John Doe", // 自定义字段 "admin": true, // 自定义字段 "iat": 1516239022, // 签发时间 "exp": 1516242622 // 过期时间 (非常重要) } 

Base64Url 编码后,构成第二部分。

生产高危警告
Payload 只是进行了 Base64 编码,并没有加密! 任何人拿到 Token 都能解码看到 Payload 内容。
绝对不要在 Payload 中放入密码、手机号等敏感信息!

3. Signature(签名)

1)Signature 的本质:消息摘要 + 密钥

Signature 的本质是一个 MAC(Message Authentication Code)

用密钥对一段消息做不可逆摘要

它同时解决两个问题:

  1. 完整性(Integrity):内容有没有被改
  2. 身份认证(Authenticity):是不是“我”签的

2)签名到底签了什么

以最常见的 HS256(HMAC + SHA256) 为例:

signature = HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret ) 
注意三个重点(面试/实战必考):
1. 被签名的是 Header + Payload
  • 不是只签 Payload
  • Header 里包含算法类型 alg
  • 改 Header 或 Payload 任意一个字节,签名都会失效
2. 使用的是 对称密钥(Secret)
  • 签名 & 验证使用同一个 Secret
  • 谁拿到 Secret,谁就可以:
    • 伪造 Token
    • 提权(admin: true)
3. 这是不可逆的
  • 无法从 Signature 推导出 Payload
  • 也无法从 Payload 推导出 Secret

3)一步一步看签名是如何生成的

假设我们有:

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

Base64Url 编码后:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 

Payload
{ "sub": "1001", "admin": false, "exp": 1700000000 } 

Base64Url 编码后:

eyJzdWIiOiIxMDAxIiwiYWRtaW4iOmZhbHNlLCJleHAiOjE3MDAwMDAwMDB9 

拼接待签名字符串
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJzdWIiOiIxMDAxIiwiYWRtaW4iOmZhbHNlLCJleHAiOjE3MDAwMDAwMDB9 

使用 Secret 做 HMAC
HMACSHA256(data, secret) 

得到 Signature:

Xk8Zk0gQZKZP6u9M1KxZPzXqZk8rQ2kR2WZc9F7d2Gs 

最终 JWT
Header.Payload.Signature 

4)为什么篡改 Payload 一定会失败?

假设黑客做了这件事:

{ "admin": false } ↓ { "admin": true } 

恶意攻击者能做到什么?

  •  能解码 Payload(Base64 是明文)
  •  无法生成新的合法 Signature

因为Secret 不在黑客手里

HMACSHA256(新Header + 新Payload, ???) 

服务器验证时做了什么?

服务器收到 Token 后会:

  1. 拆分 Header.Payload.Signature
  2. 使用自己的 Secret重新计算一次 Signature
  3. 对比:
    • 一致 → Token 没被改
    • 不一致 → Token 被篡改,直接 401
重点结论
JWT 的安全性完全依赖 Secret 是否泄露

三、标准认证流程

  1. 登录:用户提交用户名密码。
  2. 签发:服务端验证通过,生成 JWT(包含用户ID、过期时间等),返回给客户端。
  3. 存储:客户端收到 JWT,存储在 LocalStorage 或 Cookie 中。
  4. 请求:客户端再次发起请求时,在 HTTP Header 中携带:Authorization: Bearer <token>
  5. 验签:服务端拦截请求,解析 JWT,验证签名是否正确、是否过期。
    • 验证通过:放行,提取 Payload 中的用户 ID 进行业务逻辑。
    • 验证失败:返回 401 Unauthorized。

四、JWT 的致命缺陷与解决方案(生产级)

JWT 虽好,但它有一个核心缺陷:一旦签发,无法撤回(Stateless)

1. 无法强制登出(Logout 问题)

因为服务端不存状态,用户点击“注销”后,只要 Token 还没过期,如果被黑客截获,依然可以使用。

解决方案:

  • 黑名单机制(Blacklist):注销时将 Token ID ( jti == JWT ID ) 存入 Redis,设置过期时间等于 Token 的剩余有效期。每次校验时查一下 Redis。
    • 缺点:引入了状态,违背了 JWT 无状态初衷(但在生产中是必要的折中)。

2. 续签问题(Refresh Token)

JWT 过期时间设太长不安全,设太短用户体验差(老是需要重新登录)。

最佳实践:双 Token 机制

  • Access Token:有效期短(如 15 分钟),用于请求资源。
  • Refresh Token:有效期长(如 7 天),仅用于获取新的 Access Token。

流程:

  1. Access Token 过期,请求返回 401。
  2. 客户端自动携带 Refresh Token 请求 /refresh 接口。
  3. 服务端验证 Refresh Token 合法,返回新的 Access Token。
  4. 如果 Refresh Token 也过期了,强制用户重新登录。

五、JWT vs Session 对比总结

维度SessionJWT
状态存储服务端(内存/Redis)客户端(自带数据)
扩展性差(需 Session 共享)极好(无状态)
安全性防 CSRF 较麻烦,需防 Session 劫持需防 XSS,签名防篡改
RESTful不符合(有状态)符合(无状态)
性能需查库/查缓存CPU 计算签名(略耗 CPU)
注销容易(服务端删 Session)难(需黑名单机制)

六、安全避坑 Checklist

在生产环境使用 JWT,请务必检查以下几点:

  1. 必须使用 HTTPS:防止 Token 在传输过程中被中间人窃听。
  2. 算法安全:验证 Header 中的 alg,防止黑客将算法修改为 None(空算法攻击)。
  3. 不要存敏感数据:Payload 仅仅是 Base64 编码,谁都能看。
  4. 密钥保管:Secret 是命根子,绝对不能硬编码在代码里,要放在环境变量或配置中心。
  5. 存储位置
    • 建议存 HTTPOnly Cookie(防 XSS,但需处理 CSRF)。
    • 存 LocalStorage(方便,但容易被 XSS 攻击读取)。

 JWT 规范:RFC 7519

以上就是笔者对于 JWT 技术的讲解,如有错误,欢迎指正!

Read more

OpenCode 踩坑记:GitHub Copilot 按次计费?我的账单为何暴涨 3 倍!

OpenCode 踩坑记:GitHub Copilot 按次计费?我的账单为何暴涨 3 倍!

从发现问题到深度分析,一篇文章搞懂 OpenCode + GitHub Copilot 的正确打开方式 🌟 前言:一个意外的"惊喜" 进入2026年,朋友圈和技术群里都在讨论一个新的AI开发工具 —— OpenCode,号称是 AI 编程助手的"终极形态",支持 GitHub Copilot、Claude、GPT-4 等多种模型,还能自动执行多步任务。 作为一个爱折腾的程序员,我立马下载试用。我有 GitHub Copilot 企业订阅,而且OpenCode还支持,用起来应该不花钱吧? 结果一周后,我收到了公司 IT 部门的"温馨提醒" 📧: “您的 Copilot 使用量是团队平均水平的 3 倍,请注意合理使用…” 什么情况??我明明只是让

Llama-factory 详细学习笔记:第六章:DPO (直接偏好优化) 实战 (难点)

第六章:DPO (直接偏好优化) 实战 (难点) 在SFT之后,我们的模型学会了“说话”,但它的回答可能仍然是“正确的废话”,或者在面对开放性问题时,其回答的安全性、有用性和真实性仍有待提高。传统的解决方案是强化学习(RLHF),即先训练一个奖励模型(RM),再用这个RM作为环境,通过复杂的强化学习算法(如PPO)来优化语言模型。然而,RLHF流程复杂、训练不稳定、且对计算资源要求极高,令许多开发者望而却步。 直接偏好优化 (Direct Preference Optimization, DPO) 的出现,如同一道曙光,彻底改变了这一局面。它以一种极其优雅和高效的方式,实现了与RLHF相媲美甚至更好的对齐效果,但训练成本和复杂度却大大降低。本章将深入剖析DPO的核心思想、重难点配置,并通过详尽的实战步骤,带你完整地跑通一个DPO训练流程,真正让你的模型“更懂人心”。 6.1 为什么需要 DPO? (轻理论:替代 PPO,

大模型应用:语音转文本(ASR)实践:OpenAI Whisper精准转录解析.21

大模型应用:语音转文本(ASR)实践:OpenAI Whisper精准转录解析.21

一、前言         前面我们详细介绍了文本转语音的细节和实践,今天我们继续探讨一下语音转文本(ASR),初次接触,OpenAI Whisper 是最易上手、效果最均衡的开源大模型,它无需复杂的专业知识,一行代码就能实现多语言语音转写,且在噪声、口音、多语言场景下的表现远优于传统 ASR。         今天我们从基础概念入手,逐行拆解代码、详解核心参数,结合实际场景选择参数提升转录准确性,覆盖从零基础运行到精准适配场景的全流程,所有内容优先讲解基础点,确保我们都能理解、能举一反三的可用复用。 二、基础概念 1. 语音转文本(ASR) ASR,全称Automatic Speech Recognition,即自动语音识别,核心是把人类说话的音频信号转换成文字。日常用的微信语音转文字、会议纪要自动生成,本质都是 ASR 技术。 核心评价指标:字错率(WER),简单理解为 “转错的字数/总字数”,数值越低,转录越准确(比如 WER=

VsCode远程连接服务器后安装Github Copilot无法使用

VsCode远程连接服务器后安装Github Copilot无法使用

VsCode远程连接服务器后安装Github Copilot无法使用 1.在Vscode的settings中搜索Extension Kind,如图所示: 2.点击Edit in settings.json,添加如下代码: "remote.extensionKind":{"GitHub.copilot":["ui"],"GitHub.copilot-chat":["ui"],} remote.extensionKind 的作用 这是 VS Code 的远程开发配置项,用于控制扩展在远程环境(如 SSH、容器、WSL)中的运行位置。可选值: “ui”:扩展在本地客户端运行 “workspace”:扩展在远程服务器运行 这两个扩展始终在 本地客户端运行,