news 2026/5/10 20:01:38

一篇看懂JWT:Web安全的“身份证”

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
一篇看懂JWT:Web安全的“身份证”

诸神缄默不语-个人技术博文与视频目录

文章目录

  • 什么是JWT?一个简单的比喻
  • 为什么需要JWT?
  • JWT长什么样?
    • 1. 头部(Header)
    • 2. 载荷(Payload)
    • 3. 签名(Signature)
  • 用Python玩转JWT
    • 场景1:用户登录后生成JWT
    • 场景2:验证收到的JWT
    • 场景3:完整的登录验证流程
  • JWT的实际应用场景
    • 1. **单点登录(SSO)**
    • 2. **API身份验证**
    • 3. **信息交换**
  • 重要安全注意事项
    • ✅ **应该做的:**
    • ❌ **不要做的:**
  • 常见问题解答
  • 总结

什么是JWT?一个简单的比喻

想象一下你去参加一个大型会议。第一次入场时,工作人员检查你的购票信息,确认无误后给你戴上一个手环。之后在会议期间,你进出各个分会场、领取茶歇、参加活动,只需要亮出手环就可以了,不需要反复出示购票凭证。

JWT(JSON Web Token)就是这个数字世界的“手环”。它是一种让Web应用安全传递信息的方式,解决了“如何证明你是你”的问题。

为什么需要JWT?

在传统网站中,服务器通过“会话”(Session)记录用户登录状态。但这有几个问题:

  1. 服务器需要存储大量会话数据,用户多了内存压力大
  2. 难以扩展,多台服务器之间要同步会话信息
  3. 不适合移动端和API服务

JWT的出现解决了这些问题:信息都存在令牌里,服务器不用存,只需要验证令牌是否有效即可。

JWT长什么样?

一个JWT看起来像这样(实际是一长串,这里折行显示):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ. SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

它由三部分组成,用点(.)分隔:

  • 头部(Header)

  • 载荷(Payload)

  • 签名(Signature)

1. 头部(Header)

就像信封的“说明标签”,告诉别人这个令牌的基本信息:

{"alg":"HS256",// 签名算法:HS256"typ":"JWT"// 类型:JWT}

2. 载荷(Payload)

这是令牌的“核心内容”,存放实际要传递的信息:

{"sub":"1234567890",// 用户ID"name":"John Doe",// 用户名"iat":1516239022,// 签发时间"exp":1516242622// 过期时间}

3. 签名(Signature)

这是最关键的部分!它像“防伪标识”,确保令牌没有被篡改。

签名的生成方式:

HMACSHA256( base64UrlEncode(头部) + "." + base64UrlEncode(载荷), 密钥 )

用Python玩转JWT

让我们通过代码实际体验一下JWT的使用。首先安装必要的库:

pipinstallPyJWT

场景1:用户登录后生成JWT

importjwtimportdatetime# 密钥(重要!实际项目中要从安全的地方获取)SECRET_KEY="my_secret_key_12345"defcreate_jwt(user_id:str,username:str)->str:""" 创建JWT令牌 """# 设置令牌的过期时间(例如:24小时后)expiration=datetime.datetime.now(datetime.timezone.utc)+datetime.timedelta(hours=24)# 构建载荷(Payload)payload={"user_id":user_id,"username":username,"exp":expiration,# 过期时间"iat":datetime.datetime.now(datetime.timezone.utc)# 签发时间}# 生成JWTtoken=jwt.encode(payload,SECRET_KEY,algorithm="HS256")returntoken# 示例:用户登录成功后生成令牌token=create_jwt("user123","张三")print("生成的JWT令牌:")print(token)print("-"*50)

场景2:验证收到的JWT

importjwtfromtypingimportDict# 密钥(重要!实际项目中要从安全的地方获取)SECRET_KEY="my_secret_key_12345"defverify_jwt(token:str)->Dict:""" 验证JWT令牌 返回解码后的数据或抛出异常 """try:# 验证并解码令牌payload=jwt.decode(token,SECRET_KEY,algorithms=["HS256"])return{"valid":True,"data":payload,"message":"令牌有效"}exceptjwt.ExpiredSignatureError:return{"valid":False,"data":None,"message":"令牌已过期"}exceptjwt.InvalidTokenError:return{"valid":False,"data":None,"message":"无效的令牌"}# 示例:验证令牌print("验证令牌结果:")result=verify_jwt(token)# 在这里输入上一节返回的JWT tokenifresult["valid"]:print("✓ 令牌有效")print(f"用户信息:{result['data']}")else:print(f"✗{result['message']}")print("-"*50)

输出:

验证令牌结果: ✓ 令牌有效 用户信息:{'user_id': 'user123', 'username': '张三', 'exp': 1766732992, 'iat': 1766646592}

场景3:完整的登录验证流程

importjwtimportdatetimefromtypingimportDict# 密钥(重要!实际项目中要从安全的地方获取)SECRET_KEY="my_secret_key_12345"defcreate_jwt(user_id:str,username:str)->str:""" 创建JWT令牌 """# 设置令牌的过期时间(例如:24小时后)expiration=datetime.datetime.now(datetime.timezone.utc)+datetime.timedelta(hours=24)# 构建载荷(Payload)payload={"user_id":user_id,"username":username,"exp":expiration,# 过期时间"iat":datetime.datetime.now(datetime.timezone.utc)# 签发时间}# 生成JWTtoken=jwt.encode(payload,SECRET_KEY,algorithm="HS256")returntokendefverify_jwt(token:str)->Dict:""" 验证JWT令牌 返回解码后的数据或抛出异常 """try:# 验证并解码令牌payload=jwt.decode(token,SECRET_KEY,algorithms=["HS256"])return{"valid":True,"data":payload,"message":"令牌有效"}exceptjwt.ExpiredSignatureError:return{"valid":False,"data":None,"message":"令牌已过期"}exceptjwt.InvalidTokenError:return{"valid":False,"data":None,"message":"无效的令牌"}# 模拟用户数据库users_db={"user123":{"password":"password123",# 实际中应该存储哈希值,而不是明文!"username":"张三","role":"user"},"admin001":{"password":"admin_pass","username":"管理员","role":"admin"}}deflogin_and_get_token(user_id:str,password:str):""" 模拟登录过程 """# 1. 检查用户是否存在ifuser_idnotinusers_db:returnNone,"用户不存在"# 2. 验证密码ifusers_db[user_id]["password"]!=password:returnNone,"密码错误"# 3. 生成JWT令牌user_info=users_db[user_id]token=create_jwt(user_id,user_info["username"])returntoken,"登录成功"defaccess_protected_resource(token:str):""" 访问需要权限的资源 """result=verify_jwt(token)ifnotresult["valid"]:returnf"访问被拒绝:{result['message']}"user_data=result["data"]returnf"欢迎{user_data['username']}!您已成功访问受保护资源。"# 模拟完整流程print("=== 完整登录访问流程 ===")# 1. 用户登录print("1. 用户登录...")token,message=login_and_get_token("user123","password123")print(f"登录结果:{message}")iftoken:print(f"获取到的令牌:{token[:50]}...")print("-"*30)# 2. 访问受保护资源print("2. 访问受保护资源...")iftoken:response=access_protected_resource(token)print(response)print("-"*30)# 3. 演示过期令牌print("3. 演示过期令牌...")# 创建一个立即过期的令牌expired_payload={"user_id":"user123","username":"张三","exp":datetime.datetime.now(datetime.timezone.utc)-datetime.timedelta(seconds=1),# 1秒前过期"iat":datetime.datetime.now(datetime.timezone.utc)-datetime.timedelta(hours=1)}expired_token=jwt.encode(expired_payload,SECRET_KEY,algorithm="HS256")response=access_protected_resource(expired_token)print(response)

输出:

=== 完整登录访问流程 === 1. 用户登录... 登录结果:登录成功 获取到的令牌:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkI... ------------------------------ 2. 访问受保护资源... 欢迎 张三!您已成功访问受保护资源。 ------------------------------ 3. 演示过期令牌... 访问被拒绝:令牌已过期

JWT的实际应用场景

1.单点登录(SSO)

用户在一个系统登录后,无需在其他关联系统重新登录。

2.API身份验证

移动App、前端应用调用后端API时携带JWT。

3.信息交换

安全地在各方之间传递信息,因为签名可以验证内容是否被篡改。

重要安全注意事项

应该做的:

  1. 使用HTTPS:防止令牌在传输中被窃取

  2. 设置合理的过期时间:通常几小时到几天

  3. 存储敏感信息要加密:载荷默认只是编码,不是加密!

  4. 密钥要足够复杂:并且定期更换

不要做的:

  1. 不要在JWT中存储密码等敏感信息

  2. 不要将密钥硬编码在代码中

  3. 不要使用弱签名算法

  4. 前端存储要注意XSS攻击(考虑使用HttpOnly Cookie)

常见问题解答

Q:JWT和Session有什么区别?

A:Session把用户状态存在服务器,JWT把状态存在令牌里发给客户端。

Q:JWT被偷了怎么办?

A:就像手环被偷一样,小偷可以冒充你。因此过期时间要短,重要操作需二次验证。

Q:如何让JWT失效?

A:JWT一旦签发,在过期前无法主动失效。解决方案:使用短有效期+刷新令牌机制,或维护一个小的令牌黑名单。

总结

JWT就像数字世界的“身份证+防伪标识”:

  • 头部说明类型和算法

  • 载荷携带实际信息

  • 签名确保不被篡改

它的优点是无状态、易扩展,适合现代分布式应用。但也要注意安全使用,特别是密钥管理和令牌存储。

希望这篇介绍能帮你理解JWT!在实际项目中,合理使用JWT能让你的应用更安全、更高效。


提示:本文示例代码用于学习演示,实际生产环境中需要考虑更多安全因素。建议使用成熟的认证库(如Authlib、Django REST Framework JWT等)来处理复杂的认证场景。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/10 20:01:33

基于微信小程序的直播带货商品数据分析系统毕设源码+文档+讲解视频

前言 本课题聚焦直播带货行业的数据化运营需求,针对当前直播商品数据分散、分析维度单一、运营决策缺乏精准数据支撑等痛点,设计开发基于微信小程序的直播带货商品数据分析系统。系统以微信小程序为核心载体,结合前端原生开发技术与后端数据处…

作者头像 李华
网站建设 2026/5/1 5:49:59

基于 S7 - 1200 和博图 15.1 的三层立体车库 PLC 设计

三层立体车库plc s7-1200 博图15.1 1、设置启动、停止按钮,且设置指示灯显示车库的开关状态; 2、7个车位的车俩可以自由存取,且车库可以实现自动存取(存取选择最优路径); 3、每个车位均有电机控制&#…

作者头像 李华
网站建设 2026/5/9 8:35:48

当图像开始跳舞:用Matlab玩转频率域滤镜

标题:基于matlab的理想滤波器和巴特沃斯滤波器设计 关键词:一阶巴特沃斯滤波器 理想滤波器 二维傅里叶变换 fft2 描述:对任意图像进行灰度化,然后进行二维傅里叶变化,设定一个阈值,对高频或者低频信号进行滤…

作者头像 李华
网站建设 2026/5/8 21:06:51

Java面试必看:ConcurrentHashMap并发度解析

文章目录Java面试必看:ConcurrentHashMap并发度解析?场景还原:面试官与我的对话什么是并发度?并发度的核心思想并发度的实现细节1. Segment数组2. 分段锁机制3. 动态调整Segment数量4. 高效的查找机制如何配置合适的并发度&#x…

作者头像 李华
网站建设 2026/4/17 20:51:43

计算机基础小题

第一章 填空题 基于(存储程序)原理的冯诺依曼计算机,其工作方式的基本特点是(按地址访问并顺序执行指令)(指令)和(数据)都存放在存储器中,(控制器…

作者头像 李华
网站建设 2026/4/21 23:02:21

Vite 在项目中的使用分析

## 📋 目录 - [Vite 工作流程](#vite-工作流程) - [开发服务器流程](#开发服务器流程) - [构建流程](#构建流程) - [插件处理流程](#插件处理流程) - [关键配置说明](#关键配置说明) - [依赖关系](#依赖关系) ## Vite 工作流程 ## 开发服务器流程mermaid ## 构建…

作者头像 李华