深入理解JWT:原理、优缺点及使用场景

https://file-one.7k7s.com//uploads/20240604/89f56a7378e381410f4dfcfab3948775.jpg
陈杰 案例分析 发布于8个月前 更新于6个月前 856

在现代Web开发中,用户身份认证是一个极为重要的环节。随着应用架构逐渐趋向分布式,传统的会话认证逐渐暴露出种种不足,而**JWT(JSON Web Token)**作为一种基于Token的认证机制,凭借其轻量化、跨语言等特点,迅速成为开发者的首选。

本文将深入解析JWT的工作原理、结构组成、优缺点及其常见的使用场景,帮助您全面了解JWT并在实际项目中正确地使用它。


一、什么是JWT?

JWT(JSON Web Token)是一种基于JSON格式的令牌(Token),它是一种开放标准(RFC 7519),用于在各方之间安全地传递信息。JWT通常用于认证和授权场景中。

JWT的核心思想是:将用户身份信息通过数字签名加密后生成一个令牌,客户端携带该令牌与服务器交互,完成认证和授权操作。


二、JWT的结构

JWT由三部分组成,每部分之间用.分隔,完整的JWT格式如下:

Header.Payload.Signature

1. Header(头部)

Header 包含两部分信息:

  • 类型(typ):固定为 "JWT"。
  • 算法(alg):声明使用的签名算法,如 HMAC SHA256 或 RSA。

示例:

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

Header 使用 Base64 编码后可能长成这样:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

2. Payload(载荷)

Payload 是JWT的主体部分,包含需要传递的用户信息(Claims),它通常分为以下三类:

  • Registered Claims(标准声明):如 iss(签发者)、exp(过期时间)、sub(主题)、aud(受众)。
  • Public Claims(公共声明):自定义的公共信息,需避免冲突。
  • Private Claims(私有声明):双方约定的信息。

示例 Payload:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true,
  "iat": 1516239022,
  "exp": 1516242622
}

Payload 使用 Base64 编码后可能长成这样:

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMiwiZXhwIjoxNTE2MjM5MzIyfQ

3. Signature(签名)

签名用于验证JWT的完整性,确保Token未被篡改。签名的生成公式如下:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret
)

生成的签名示例:

SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

最终得到的JWT完整格式如下:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMiwiZXhwIjoxNTE2MjM5MzIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

三、JWT的工作流程

  1. 用户登录:用户通过用户名和密码向服务器发起登录请求。
  2. 服务器生成JWT
    • 验证用户身份后,服务器使用预定义的密钥(Secret)创建JWT。
    • JWT中包含用户数据及过期时间。
  3. 客户端存储JWT
    • 客户端(例如浏览器或移动端)将JWT存储在LocalStorageHTTP Only Cookie中。
  4. 客户端携带JWT访问资源
    • 客户端每次向服务器发送请求时,在请求头的 Authorization 字段中携带JWT:
      Authorization: Bearer <JWT>
      
  5. 服务器验证JWT
    • 服务器使用密钥验证JWT的合法性。
    • 验证通过则返回资源,验证失败则返回 401 Unauthorized

四、JWT的优缺点

优点

  1. 无状态认证
    • JWT是无状态的,服务器无需存储会话信息,降低了服务器压力,更适合分布式系统。
  2. 跨语言支持
    • JWT是基于JSON的,能够在不同语言和平台之间无缝传递。
  3. 高效
    • JWT一次生成后,后续请求只需携带JWT即可,无需多次查询数据库。
  4. 可扩展性
    • Payload可携带自定义信息,满足不同业务需求。

缺点

  1. 存在安全隐患
    • JWT一旦被窃取,除非过期,否则攻击者可以使用它进行伪装。
  2. Token不可撤销
    • JWT是无状态的,无法轻易地使某个已签发的Token失效(除非引入额外的黑名单机制)。
  3. Payload可以被解码
    • 虽然JWT经过签名,但Payload部分是可解码的,敏感数据必须加密或避免直接暴露在Payload中。

五、JWT的常见使用场景

1. 用户认证

JWT最常见的用途是用户认证,通过生成的Token验证用户身份。多用于:

  • Web应用登录认证
  • 移动端用户认证
  • 第三方应用OAuth认证

2. 单点登录(SSO)

在分布式系统或微服务架构中,SSO是一个重要的需求。JWT可以跨服务传递用户身份信息,实现无缝登录。


3. API认证

在RESTful API中,JWT常用于保护接口,避免未授权的访问。


4. 临时权限控制

通过设置短时效的JWT(如15分钟有效),可以满足一些临时的权限需求,例如一次性访问链接、验证码等。


六、如何安全地使用JWT?

  1. 使用HTTPS
    • 确保通信加密,防止Token被中间人窃取。
  2. 设置合理的过期时间
    • 为JWT设置较短的过期时间,减少Token被滥用的风险。
  3. 使用HTTP Only Cookie存储Token
    • 避免Token被JavaScript脚本获取,防止XSS攻击。
  4. 避免在Payload中存储敏感信息
    • Payload是可解码的,敏感数据应加密或不存储在Token中。
  5. 引入黑名单机制
    • 在某些场景下,创建Token黑名单机制以支持Token撤销。
  6. 定期更换密钥
    • 定期更新JWT签名密钥,提升安全性。

七、JWT常见问题解答

1. 为什么Payload可以被解码?

JWT的Payload是Base64编码的,主要目的是便于传输,而不是加密。敏感信息不要直接存储在Payload中。

2. JWT和Session的区别是什么?

  • Session:服务器存储会话信息,适合小规模应用。
  • JWT:无状态,客户端存储Token,适用于分布式系统。

3. 如何使JWT失效?

  • 等待JWT过期。
  • 使用黑名单机制。
  • 修改签名密钥,使先前的JWT失效。

八、总结

JWT是一种高效、跨平台的认证机制,在现代Web开发中得到了广泛应用。然而,在使用JWT时,必须注意其安全性限制,并结合具体业务场景合理设计。例如,可以利用短时效Token避免滥用,或者配合黑名单机制解决不可撤销的问题。

通过正确地理解和使用JWT,您将能够构建更加高效、可靠的身份认证系统。

THE END

喜欢就支持一下吧!

版权声明:除却声明转载或特殊注明,否则均为艾林博客原创文章,分享是一种美德,转载请保留原链接,感谢您的支持和理解

静止便是死亡,只有运动才能敲开永生的大门。

泰戈尔

推荐阅读

PHP中的任意精度数学计算:探索BCMath扩展

详细介绍使用PHP BCMath扩展进行高精度数学计算的方法,包括加法、减法、乘法、除法、求余、乘方、平方根计算以及设置...

https://file-one.7k7s.com//uploads/20240604/89f56a7378e381410f4dfcfab3948775.jpg
陈杰 03月07日

高效后端开发:实践与技巧

本篇文章分享了如何通过选择合适的编程语言与框架、优化数据库查询、使用异步编程、实施微服务架构等方法提升后端开发的效率和性...

https://file-one.7k7s.com//uploads/20240604/89f56a7378e381410f4dfcfab3948775.jpg
陈杰 11月09日

深入浅出:后端开发中的缓存机制

这篇文章深入探讨了后端开发中的缓存机制,包括缓存的定义、分类、常见使用场景、挑战与解决方案,以及如何选择合适的缓存工具,...

https://file-one.7k7s.com//uploads/20240604/89f56a7378e381410f4dfcfab3948775.jpg
陈杰 01月15日

深度探索 PHP 8 注解:从基础概念到高级应用

本文全面深入地探讨了 PHP 8 注解,从基础概念、原理分析到自带注解详解与高级应用实践,为开发者提供了关于注解的全方位...

https://file-one.7k7s.com//uploads/20240604/89f56a7378e381410f4dfcfab3948775.jpg
陈杰 03月12日

16个PHP开发者必知必会的魔术方法

本文列举了16个PHP开发者应当掌握的魔术方法,涵盖了它们的定义、使用场景和实现技巧,为PHP开发提供重要参考。

https://file-one.7k7s.com//uploads/20240604/89f56a7378e381410f4dfcfab3948775.jpg
陈杰 03月22日

深入解析 JavaScript 和 TypeScript 的区别:选型和实战指南

本文详细解析了 JavaScript 和 TypeScript 的核心区别,包括类型系统、开发体验、错误检测等方面,并通...

https://file-one.7k7s.com//uploads/20240604/89f56a7378e381410f4dfcfab3948775.jpg
陈杰 12月28日

PHP 代码优化指南:善用命名参数打造清晰可维护的代码

本文全面解析 PHP 8 引入的命名参数特性,详细介绍其优势、最佳实践与注意事项,并结合实际代码示例,帮助开发者编写更优...

https://file-one.7k7s.com//uploads/20240604/89f56a7378e381410f4dfcfab3948775.jpg
陈杰 12月24日

thinkphp 模型withCount方法如何指定COUNT字段

本文将详细介绍如何在 ThinkPHP 模型中使用 withCount 方法来获取关联模型的计数信息。通过指定 COUN...

https://file-one.7k7s.com//uploads/20240604/89f56a7378e381410f4dfcfab3948775.jpg
陈杰 01月03日