开发必会:JWT技术揭秘,一次性拿捏

1. 引言

现在前后端分离项目已经成为 主流的开发模式,而在项目开发过程中多多少少都会接触到登录相关的业务,几乎是绕不开的一部分。而只要涉及到登录模块,大部分的开发中都会用提到一种叫做token的东西,顾名思义,token就是一个令牌,用来作用户身份校验的一种技术,或者具体点说,token不过是一串含有特定用户身份信息的字符串。一般由后端颁发,前端携带。

可能提到token,很多人会不自觉的将它和接下来要重点介绍的JWT联系到一起,甚至可能不少人都会以为JWTToken不就是同一个东西吗?并不完全是。Token是一个比较宽泛的定义,而在具体的实现上,Token有很多实现方式,JWT就是其中的一种,也是日常开发中最常见的一种token实现,不管是在单体项目还是分布式微服务中,JWT技术都被广泛的应用,因此,有必要一次性将它安排的明明白白!


2. JWT五脏六腑

2.1 长什么样

JWT的缩写是JSON Web Token。常用在网络应用环境中传递声明一种紧凑自包含的方式,这些声明可以被验证和信任,因为他是经过数字签名的,JWT可以被用于身份认证和信息交换。我靠,有一说一,这定义真的是抽象,但是不打紧,你不用也没必要去记下他的定义,你要学的,是理解他的原理和作用即可,就开发行业来说,很多技术其实没那么注重对名词本身的记忆上,更多的是对技术原理和使用的要求,当你学会如何使并理解了他背后的实现原理之后,你也就掌握了这门技术,晦涩的术语定义不过是回个头的事。

先看个实际项目中基于JWT实现的Token字符串,这是来自我的个人博客登录成功之后的响应数据,其中就包含了token字段。

image-20240422145939177

为了更好的理解JWT,下面以一个具体的例子作为切入进行讲解。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

仔细观察这串字符,他其实被一个点.分割成了三部分:

image-20240422151408847


2.2 组成

JWT

如上面的图所示,JWT由三个部分构成,从左到右以.分割,分别为:

  • Header头部
  • Payload(载荷)
  • Signature(签名)

image-20240422151839638

2.2.1 Header

头部通常是包含了两部分信息:

  • 令牌类型(比如这里为JWT)
  • 使用的签名算法(比如这里用的是HS256)
{
  "alg": "HS256",
  "typ": "JWT"
}

令牌类型除了JWT之外,一般还有:JWEJWS,这不是本文的重点,当作顺手牵羊知道有这东西就行。而对于签名算法,这里用到的是哈希256算法,这只是其众多算法的一种,常用的还有:

  1. RS256(RSA using SHA-256):RSA 非对称加密算法结合 SHA-256 哈希算法进行签名。在这种情况下,使用私钥对数据进行签名,然后使用公钥进行验证。
  2. ES256(ECDSA using P-256 and SHA-256):使用椭圆曲线数字签名算法(ECDSA)和 SHA-256 哈希算法进行签名。这是基于椭圆曲线加密的一种签名算法。
  3. HS384(HMAC using SHA-384):使用 HMAC(Hash-based Message Authentication Code)和 SHA-384 哈希算法进行签名。
  4. RS384(RSA using SHA-384):RSA 非对称加密算法结合 SHA-384 哈希算法进行签名。
  5. ES384(ECDSA using P-384 and SHA-384):使用椭圆曲线数字签名算法(ECDSA)和 SHA-384 哈希算法进行签名。
  6. HS512(HMAC using SHA-512):使用 HMAC 和 SHA-512 哈希算法进行签名。
  7. RS512(RSA using SHA-512):RSA 非对称加密算法结合 SHA-512 哈希算法进行签名。
  8. ES512(ECDSA using P-521 and SHA-512):使用椭圆曲线数字签名算法(ECDSA)和 SHA-512 哈希算法进行签名。

不同的算法实现原理不同,但启用算法对签名进行加密的唯一共性就是用来确保数据的完整性和真实性:

  1. 数据完整性验证:签名算法通过对数据进行签名,生成一个固定长度的字符串,这个字符串会随着 JWT 一起发送。接收方可以使用相同的密钥和签名算法重新计算签名,然后将计算出的签名与接收到的签名进行比较,以验证数据在传输过程中是否被篡改。
  2. 数据真实性验证:签名算法使用发送方的密钥对数据进行签名,接收方使用相同的密钥来验证签名。如果接收方能够成功验证签名,就可以确定数据确实是由发送方生成的,从而验证数据的真实性。
  3. 防止伪造和篡改:通过签名算法生成的签名可以有效防止恶意第三方伪造数据或篡改数据。即使数据在传输过程中被修改,接收方也能够通过验证签名来检测出数据的篡改。
  4. 身份验证:签名算法还可以用于验证数据的发送方身份。只有知道正确密钥的发送方才能生成有效的签名,因此接收方可以通过验证签名来确认数据的发送方身份。

2.2.2 Payload

载荷部分包含了声明(claims),声明关于实体(比如用户)和其他数据的信息,载荷部分通常是一个 JSON 对象,以结构化的方式包含了各种声明和数据信息,并被Base64编码以提供轻量级的传输。

为了在网络上进行传输,JWT 的各个部分(包括头部、载荷和签名)通常会被 Base64 编码。Base64 编码是一种将二进制数据转换为文本的编码方式,它可以确保数据在传输过程中不会丢失,并且可以减少传输数据的大小。

也即是说,载荷部分是我们存储用户信息的地方,这些用户信息一般以JSON格式进行存储,比如:

{
    "username":"Gemini48",
    "money":0
}

但是请注意,不建议将用户敏感信息存入JWT中,这是不安全的做法。为什么不安全,因为没有经过加密啊,注意上上面提到的 Base64进行编码,注意Base64只是一种编码方式,而不是加密算。所以说经过编码后的数据依旧是可逆的,容易被网络大黑客给你解码出来原文,想象一下,一旦你的敏感数据被以这种方式存储在JWT中,比如你在某知名交友网站的登录密码和用户名,那就相当于向互联网宣布自己的密码正在裸奔,被别人拿去扒出来你身兼数职做添狗的那几十页聊天记录…

所以请务必记住:

  • JWT不要存敏感信息!
  • JWT不要存敏感信息!
  • JWT不要存敏感信息!

我们话又说回来,即使使用了加密算法,也无法完全保证这些信息的安全性。有一部叫《我是谁》的电影我觉得挺好看的,这是一部黑客题材的电影,里面有一句话我觉得很经典:没有绝对安全的系统!


2.2.3 Signature

签名是对头部和载荷的内容进行签名后得到的一段字符串,用于验证 JWT 的真实性和完整性。签名通过将头部、载荷以及密钥一起进行加密生成,确保 JWT 在传输过程中没有被篡改。

这部分其实上面已经多多少少说差不多了,需要注意的是,签名算法很多,具体使用哪一种没有固定不变的规则,需要根据自己的业务需求等情况来选择,不管如何加密签名,都需要对JWT进行定期轮换,在JWT中设置合理的过期时间,以确保令牌在一段时间后失效,减少令牌被滥用的可能性。image-20240422153638441


3. JWT 基本工作原理

有个问题: JWT是否可逆????

如果你不是直接点一下文章目录跳到这里的话,那我相信你的答案和我一样,JWT本身是不可逆的,其实这种说法可能不那么标准,可逆不可逆一般用在密码学领域中较多,简单来说,可逆就是指通过某种加密算法加密后的密文是否能通过某些手段再进行解密回去得到加密之前的明文的过程,一般来说,如果某种算法的加密可以被解密,那么就说这是一种可逆加密算法。

那么问题来了,既然JWT不可逆,我们在进行信息验证的时候是怎么获取到其载荷部分的用户信息呢?大致步骤如下:

  1. 解析JWT:首先,需要解析JWT,将其分解为头部、载荷和签名三个部分。这可以通过将JWT字符串拆分为这三部分来完成。
  2. 验证签名:使用JWT中的头部和载荷以及事先约定的密钥,对JWT进行签名验证。具体的验证过程取决于JWT使用的签名算法,可以是对称加密算法(如HMAC)或非对称加密算法(如RSA)。
  3. 提取载荷数据:如果签名验证成功,说明JWT未被篡改,可以提取载荷数据。载荷部分通常包含关于用户身份、权限等信息的声明。
  4. 使用载荷数据:一旦获得有效的载荷数据,可以根据需要使用这些数据来进行授权、身份验证等操作。

为了更好的理解JWT,这里推荐一个在线地址:https://jwt.io/#debugger-io,网站上可以直接根据需三部分的需求生成和解析JWT,使用方式很简单,将自己的token粘贴到左侧的Encoded中,选择签名加密算法即可解析在右侧(Decoded)部分显示。也可以直接修改右侧的三部分信息,他会在左侧实时的生成目标JWT。不得不说,这可比在代码中写demo来的方便快捷!!

image-20240422164656044

大可不必太担心你的令牌泄漏,因为:

image-20240422170220673

下面是JWTWeb开发中的基本工作原理:

image-20240422163237414

问:为什么图大都是英文啊,别问,问就是中文没有这种字体,而我挺中意这种自由自在随性风格的字体的。

虽然有图了,这里还是大致用文字的方式捋一遍:

  • 客户端向服务器发起登录请求,执行用户登录
  • 服务器生成JWT并颁发JWT响应给客户端
  • 客户端再次请求服务端其他接口时会在请求头等信息中携带JWT生成的Token信息
  • 服务端收到请求之后对请求中Token进行校验,校验通过后才会允许请求执行并响应到客户端;

4. JWT的优势

  • 无状态:由于 JWT 本身携带所有必要的信息,因此服务器不需要维护会话信息。这使得 JWT 无状态,从而减少了服务器负载并简化了可伸缩性。
  • 紧凑高效:由于其紧凑的解构,JWT 适合通过网络传输,并且易于客户端解析。
  • 安全性:JWT 经过数字签名,确保数据完整性并防止篡改。使用加密算法可以进一步增强安全性。
  • 跨域通信:JWT 可以跨不同的域或微服务使用,因为它们不依赖于 cookie 或服务器端会话。

5. 代码实践

巴拉巴拉说了这么多,最终还是要写代码的啊。老规矩,演示还是基于Gradle构建的SpringBoot项目,Maven玩家请自行变通。

下面给出Maven仓库地址,进去直接搜索关键字即可:https://mvnrepository.com/

关于Token的具体实现的依赖库有很多,这里采用com.auth0java-jwt进行演示。

5.1 添加依赖
// https://mvnrepository.com/artifact/com.auth0/java-jwt
implementation 'com.auth0:java-jwt:4.4.0'
5.2 生成Token
// 密钥,这里使用HMAC SHA-256算法举例,实际项目中应妥善保管和配置
private static final String SECRET_KEY = "DHSDNSJDSndjsdjsSAJKDS";

/**
 * 生成JWT Token
 *
 * @param issuer       签发者,通常是服务提供者的名称或URL,用于标识JWT的来源
 * @param expirationTimeInMinutes 过期时间(分钟),指定JWT的有效期限
 * @return 生成的JWT字符串,可作为Bearer Token用于HTTP请求的Authorization头
 */

public static String generateToken(String issuer, long expirationTimeInMinutes) {
    // 使用指定的密钥和HMAC SHA-256算法创建JWT签名算法实例
    Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY);
    Map<String,Object> headers = new HashMap<>();
    // 获取当前时间,并计算过期时间点
    Date now = Date.from(Instant.now());
    Date expirationDate = Date.from(now.toInstant().plusSeconds(expirationTimeInMinutes * 60));
    headers.put("CSDN:","小妖剑");

    // 创建JWT并设置必要的属性(主题、签发者、发行时间和过期时间),最后使用指定的算法签名
    return JWT.create()
            .withHeader(headers) // 头部
            .withClaim("userId", 408) // 载荷
            .withClaim("username","小妖剑") // 载荷
            .withIssuer(issuer)
            .withIssuedAt(now)
            .withExpiresAt(expirationDate)
            .sign(algorithm); // 签名算法
}

执行代码之后,我们不妨将控制台打印的token信息放到上面提到的jwt.io网站上进行解析,得到下面的结果:image-20240422182007708

注意,这个代码生成的token中,我们发现在header部分除了有我们之前说的令牌类型和签名算法信息之外,还有一个我们自定义的CSDN的字段,显然,如果我们需要在头部进行自定义信息的话,上面的写法可以参考,其实就是传入一个Map集合,在集合中定义我们需要放在头部的信息数据,但是一般情况下,我们是不需要自定义header信息的,所以上面的代码可以修改为:

/**
 * 生成JWT Token
 *
 * @param issuer       签发者,通常是服务提供者的名称或URL,用于标识JWT的来源
 * @param expirationTimeInMinutes 过期时间(分钟),指定JWT的有效期限
 * @return 生成的JWT字符串,可作为Bearer Token用于HTTP请求的Authorization头
 */

public static String generateToken(String issuer, long expirationTimeInMinutes) {
    // 使用指定的密钥和HMAC SHA-256算法创建JWT签名算法实例
    Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY);

    // 获取当前时间,并计算过期时间点
    Date now = Date.from(Instant.now());
    Date expirationDate = Date.from(now.toInstant().plusSeconds(expirationTimeInMinutes * 60));

    // 创建JWT并设置必要的属性(主题、签发者、发行时间和过期时间),最后使用指定的算法签名
    return JWT.create()
            .withClaim("userId", 408)
            .withClaim("username","小妖剑")
            .withIssuer(issuer)
            .withIssuedAt(now)
            .withExpiresAt(expirationDate)
            .sign(algorithm);
}

image-20240422182846195

关于这个jwt.io工具网站的使用,其实埋了一些小技巧的,不知道各位有没有认真观察。写完了Token的生成,接下来继续Token的解析方法。解析Token用到了java-jwt中的一个verify()方法,方法返回一个DecodedJWT对象,该对象中包含了所有token信息,我们可以看看源码:

image-20240422183832248

/**
 * 验证并解析JWT Token
 *
 * @param token 待验证的JWT字符串
 * @return 经过验证的DecodedJWT对象,包含了JWT的原始信息和已验证的claims
 * @throws JWTVerificationException 如果验证失败,例如密钥不匹配、签发者不符、过期或被篡改等
 */
public static DecodedJWT validateAndDecodeToken(String token) throws JWTVerificationException {
    // 使用指定的密钥和HMAC SHA-256算法创建JWT验证器实例
    Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY);
    JWTVerifier verifier = JWT.require(algorithm)
            // 设置期望的签发者,验证时会检查传入的JWT是否与此相符
            .withIssuer("https://www.ilikexff.cn")
            .build();

    // 使用验证器对传入的JWT进行验证,并返回解析后的DecodedJWT对象
    return verifier.verify(token);
}

image-20240422183938687

目前为止,我们使用java-jwt完成了JWT的生成和解析功能,至于如何在实际的项目中使用生成的Token,应该难不倒在看的各位了!但是这里还有一些比较重要的工作没有做,那就是测试Token的时效性,这重要但不难,就不再赘述。在我后续的文章中,也会用到JWT实现Token的登录功能,敬请关注!


感谢阅读,期待下次与你再见!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/564559.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

c语言不难说C语言难的,已经说明你根本不适合计算机编程工作

对普通人来说C语言是学习编程的最佳入门语言&#xff0c;有效培养你的编程思维&#xff0c;你有了这个基础后去学其它语言&#xff0c;你会惊讶地发现原来其它语言原来这么好学&#xff0c;现在出现一个Python说小白最适合&#xff0c;在开始前我有一些资料&#xff0c;是我根据…

Proxyman Premium for Mac:网络调试利器,开发者首选!

Proxyman Premium for Mac是一款功能强大的网络调试和分析工具&#xff0c;专为开发者和测试人员打造。这款软件以其出色的性能和丰富的功能&#xff0c;帮助用户在网络开发和调试过程中更有效地分析和拦截网络请求&#xff0c;进行必要的修改和重发&#xff0c;从而进行更深度…

渐进时间复杂度O(n)

基本操作数 算法的运行速度受计算机性能的影响&#xff0c;所以通常考虑算法效率的不是算法运行的实际用时&#xff0c;而是算法运行所需要进行的基本操作的数量。 像加减乘除、访问变量、给变量赋值等都可以看作基本操作。对基本操作的计数或是估测可以作为评判算法用时的指标…

Java中的封装

package day32; ​ public class Person {private String name;private int age; ​public String getName() {return name;} ​public void setName(String name) {this.name name;} ​public int getAge() {return age;} ​public void setAge(int age) {if (age>120 || …

webstorm 设置大括号、问号、冒号、if 或for条件 、+-*/ 运算符等两侧的空格(2024-04-18)

在setting设置里面 我这里演示javascript 【Editor-Code Style-JavaScript-Spaces】 import {Component} from react 改为 的 import { Component } from react { }内部两侧都加空格 根据自己的需求设置 [ ]大括号内部两端的空格

GenVideo、SkelFormer、EfficientGS、HOLD、Motion Synthesis、Learn2Talk

本文首发于公众号&#xff1a;机器感知 GenVideo、SkelFormer、EfficientGS、HOLD、Motion Synthesis、Learn2Talk Enabling Stateful Behaviors for Diffusion-based Policy Learning While imitation learning provides a simple and effective framework for policy learni…

优维应用级数字化架构管理:让企业运维天堑变通途

在优维科技的产品视角中&#xff0c;数字化架构管理就像是一门精妙的艺术&#xff0c;它将上层应用模型的业务概念以可视化的方式呈现出来&#xff0c;使得业务逻辑和流程变得更加直观、清晰。我们将这样的管理方式理解为“给企业搭起一座桥梁”——在这座桥梁的搭建过程中&…

Langchain入门到实战-第四弹

Langchain入门到实战 Langchain中的提示词官网地址Langchain概述Langchain的提示词用法更新计划 Langchain中的提示词 语言模型提示模板是预定义的生成语言模型提示的方法。模板可能包括指令、少样本示例、特定任务的上下文和问题。LangChain 提供了创建和处理提示模板的工具。…

BMR:基于Boostrapping多视图的虚假新闻检测

一、概述 文章提出了三种视图信息来表示一篇新闻&#xff1a;文本、图像结构、图像语义。然后设计了改进的多门混合专家系统&#xff08;iMMoE&#xff09;来进行信息融合。保留单模态信息来保证特征对新闻的保真性&#xff0c;增加的多模态信息能保证不同模态的一致性&#xf…

【python】如何通过python来发送短信

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

(2024,DiffEdit,掩码,潜在噪声校正)GenVideo:使用 T2I 扩散模型进行单样本目标图像和形状感知视频编辑

GenVideo: One-shot target-image and shape aware video editing using T2I diffusion models 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 3. 方法 3.1. 对源视频进行微调…

用Python自动化操作PPT,看完这篇文章就够了!

1.PPT自动化能干什么&#xff1f;有什么优势&#xff1f; 它可以代替你自动制作PPT它可以减少你调整用于调整PPT格式的时间它可以让数据报告风格一致总之就是&#xff1a;它能提高你的工作效率&#xff01;让你有更多时间去做其他事情&#xff01; 2.使用win32com操作ppt 官…

【Linux基础】Linux基础概念

目录 前言 浅谈什么是文件&#xff1f; Linux下目录结构的认识及路径 目录结构 路径 家目录 什么是递归式的删除 重定向 输出重定向&#xff1a; 追加重定向&#xff1a; 输入重定向&#xff1a; 命令行管道 shell外壳 为什么需要shell外壳&#xff1f; shell外壳…

Jetpack Bluetooth蓝牙MODE,这个项目使用Jetpack Bluetooth库来实现我们用于开发的一些日常功能

Jetpack蓝牙演示&#xff0c;这个项目使用Jetpack Bluetooth库来实现我们用于开发的一些日常功能[搜索&#xff0c;连接&#xff0c;发现服务&#xff0c;蓝牙操作[读&#xff0c;写&#xff0c;通知]]。 AndroidX蓝牙是Jetpack库套件的新增功能。虽然目前处于阿尔法阶段&…

【华为OD笔试】2024D卷机考套题汇总【不断更新,限时免费】

有LeetCode算法/华为OD考试扣扣交流群可加 948025485 可上全网独家的 欧弟OJ系统 练习华子OD、大厂真题 绿色聊天软件戳 od1441了解算法冲刺训练&#xff08;备注【CSDN】否则不通过&#xff09; 文章目录 2024年4月17日&#xff08;2024D卷&#xff09;2024年4月18日&#xff…

【创作活动】2023年图灵奖

2023年图灵奖揭晓&#xff0c;你怎么看&#xff1f; 2023年图灵奖&#xff0c;最近刚刚颁给普林斯顿数学教授 Avi Wigderson&#xff01;作为理论计算机科学领域的领军人物&#xff0c;他对于理解计算中的随机性和伪随机性的作用&#xff0c;作出了开创性贡献。提醒&#xff1…

前端学习<四>JavaScript基础——42-事件的传播和事件冒泡

DOM事件流 事件传播的三个阶段是&#xff1a;事件捕获、事件冒泡和目标。 事件捕获阶段&#xff1a;事件从祖先元素往子元素查找&#xff08;DOM树结构&#xff09;&#xff0c;直到捕获到事件目标 target。在这个过程中&#xff0c;默认情况下&#xff0c;事件相应的监听函数…

CCF PTA 2023年11月C++卫星发射

【问题描述】 在 2050 年卫星发射技术已经得到极大发展&#xff0c;我国将援助 A 国建立远轨道卫星导航系统&#xff0c;该项目计划第 一个天发射一颗卫星&#xff1b;之后两天&#xff08;第二天和第三天&#xff09;&#xff0c;每天发射两颗卫星&#xff1b;之后三天&#…

4.点云数据的配准

1.点云配准ICP(Iterative Closest Point)算法 点云配准的原理及ICP(Iterative Closest Point)算法原理参照博客【PCL】—— 点云配准ICP(Iterative Closest Point)算法_icp点云配准-CSDN博客。 &#xff08;1&#xff09;点云配准原理&#xff1a;三维扫描仪设备对目标物体一…

Spring Cloud Gateway详细介绍以及实现动态路由

一. 简介 Spring Cloud Gateway This project provides a libraries for building an API Gateway on top of Spring WebFlux or Spring WebMVC. Spring Cloud Gateway aims to provide a simple, yet effective way to route to APIs and provide cross cutting concerns to …