JWT从入门到精通:一文解锁生成、验证与防篡改秘籍

JWT从入门到精通:一文解锁生成、验证与防篡改秘籍

JWT 是什么

JWT,即 JSON Web Token,是一种基于 JSON 的开放标准(RFC 7519),用于在网络应用间安全地传输信息 。简单来说,它就像是一把特殊的钥匙,这把钥匙里包含了用户的一些关键信息。当你登录一个应用时,服务器会生成这样一把 "钥匙" 给你,之后你拿着这把 "钥匙" 去访问应用的各种功能,服务器通过检查这把 "钥匙" 就能知道你是谁,是否有权限进行操作。

在实际应用中,JWT 最常见的场景就是身份验证和信息交换。比如,当你登录淘宝时,输入账号密码成功后,服务器会返回一个 JWT 给你的手机或电脑。之后你在浏览商品、添加购物车、下单等操作时,请求里都会带上这个 JWT,淘宝的服务器通过验证这个 JWT,就能确认是你在操作,而不是别人冒充你。又比如在一些微服务架构的系统中,各个服务之间需要传递用户信息来协同工作,JWT 就可以用来安全地传输这些信息,保证信息在传递过程中的完整性和真实性。

了解了 JWT 的基本概念和应用场景后,接下来我们就深入到 JWT 的内部,看看它是如何生成、验证以及防止被篡改的,这也是掌握 JWT 技术的关键所在。

JWT 的结构剖析

在深入了解 JWT 的生成、验证与防篡改之前,我们先来剖析一下 JWT 的内部结构。JWT 就像是一个特殊的包裹,它由三个部分组成,分别是 Header(头部)、Payload(载荷)和 Signature(签名) ,这三个部分通过点号(.)连接,形成一个完整的 JWT 字符串 ,就像这样:xxxxx.yyyyy.zzzzz 。接下来,我们就详细看看这三个部分各自的作用和奥秘。

Header(头部)

Header 是 JWT 的 "身份铭牌",主要描述 JWT 的元数据,其中最关键的是声明签名算法和令牌类型。比如下面这个典型的 Header:

json 复制代码
{
  "alg": "HS256",
  "typ": "JWT"
}

在这段 JSON 代码里,alg字段指定了签名使用的算法,这里的HS256表示使用 HMAC SHA-256 算法;typ字段则表明了令牌类型,JWT代表这是一个 JSON Web Token。当服务器生成 JWT 时,会先将这个 Header 对象进行 Base64Url 编码 ,Base64Url 编码是一种针对 URL 安全的 Base64 编码方式,编码后的结果就成为了 JWT 的第一部分。例如,上述 Header 经过 Base64Url 编码后,得到的字符串是:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 。需要注意的是,Base64Url 编码并不是加密,所以 Header 部分的内容任何人都可以解码查看,它只是以一种特定的格式来携带 JWT 的基本信息。

Payload(载荷)

Payload 是 JWT 的 "信息背包",是承载实际业务数据的部分,这些数据以 "声明(Claims)" 的形式存在。声明可以分为以下几类:

  • 标准声明(Registered Claims):这是一组预定义的声明,虽然不是强制使用,但推荐使用,它们为 JWT 提供了一些通用的、可互操作的信息。常见的标准声明有:

    • iss(issuer):签发者,标识 JWT 是由哪个实体生成的,比如auth.example.com ,表明这个 JWT 是由auth.example.com这个认证服务器签发的。

    • sub(subject):主题,通常用来标识 JWT 所面向的用户或实体,一般是用户的唯一 ID,例如123456 ,代表这个 JWT 是关于 ID 为123456的用户。

    • aud(audience):接收方,指定 JWT 的预期接收者,可以是一个或多个实体,比如["client1", "client2"] ,表示这个 JWT 可以被client1client2接收使用。

    • exp(expiration time):过期时间,用 Unix 时间戳表示,一旦当前时间超过这个时间戳,JWT 就会被视为过期,例如1616239022 ,对应的实际时间可能是某个具体的日期和时刻,超过这个时间后,该 JWT 就不再有效。

    • nbf(not before):生效时间,在此时间之前 JWT 无效,同样是 Unix 时间戳格式,比如1616238022 ,表示在这个时间点之前,即使 JWT 被收到,也不能被认为是有效的。

    • iat(issued at):签发时间,记录 JWT 的生成时间,也是 Unix 时间戳,如1616237022 ,可以用于追踪 JWT 的创建时刻。

  • 公共声明(Public Claims) :这是可以由应用程序自定义的声明,为了避免命名冲突,最好在 IANA JSON Web Token Registry 中定义它们,或者使用一个防冲突的命名空间,比如包含域名。例如,我们可以定义一个username声明来表示用户的用户名,或者定义一个role声明来表示用户的角色,如adminuser

  • 私有声明(Private Claims) :这是在 JWT 的提供者和消费者之间预先约定好的自定义声明,用于在双方之间共享特定的信息,既不属于标准声明也不属于公共声明。比如,应用程序内部可能约定一个userPreferences声明来存放用户的个性化设置信息。

一个包含业务数据的 Payload 示例如下:

json 复制代码
{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022,
  "admin": true
}

这里sub表示用户 ID,name是用户姓名,iat记录了签发时间,admin则是一个自定义的私有声明,用于表示该用户是否是管理员。和 Header 一样,Payload 中的 JSON 对象也会通过 Base64Url 编码,成为 JWT 的第二部分。上述 Payload 经过 Base64Url 编码后得到:eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJhZG1pbiI6dHJ1ZX0 。同样要牢记,Payload 只是经过了编码,并非加密,所以不要在其中存放敏感信息,比如用户密码等,因为这些信息可以被轻易解码查看。

Signature(签名)

Signature 是 JWT 的 "安全锁",是保证 JWT 不被篡改的核心部分。签名的生成过程是这样的:首先,将编码后的 Header 和编码后的 Payload 用点号(.)连接起来,形成一个新的字符串,即base64UrlEncode(header) + "." + base64UrlEncode(payload) ;然后,使用在 Header 中指定的签名算法(如HS256),以及一个只有服务器知道的密钥(Secret) ,对这个连接后的字符串进行签名。以HS256算法为例,签名公式为:signature = HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret) 。最后,将签名结果(一个二进制哈希值)也进行 Base64Url 编码,形成 JWT 的第三部分。

假设我们的密钥是字符串"your-256-bit-secret" ,对eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJhZG1pbiI6dHJ1ZX0进行 HMAC - SHA256 签名并编码后,得到的第三部分可能是:SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c 。签名的关键作用在于,当服务器收到 JWT 后,会用同样的密钥和算法重新计算前两部分的签名,如果计算结果与 JWT 中的第三部分签名匹配,就说明 JWT 在传输过程中没有被篡改,是可信的;如果不匹配,那就意味着 JWT 可能被恶意修改过,服务器会立即拒绝这个 JWT,从而保证了数据的完整性和安全性。

JWT 的生成步骤

了解了 JWT 的结构之后,我们就可以开始学习如何生成 JWT 了。JWT 的生成过程就像是制作一把特殊的钥匙,每一个步骤都至关重要,下面我们就逐步来揭开它的神秘面纱 。

准备工作

在生成 JWT 之前,我们需要确定三个关键要素:

  • 算法 :选择一种签名算法,常见的有HS256(HMAC SHA-256)、RS256(RSA SHA-256)等 。HS256是一种对称加密算法,使用同一个密钥进行签名和验证,它的优点是简单高效,适合在客户端和服务器之间共享密钥的场景;RS256则是非对称加密算法,使用私钥进行签名,公钥进行验证,安全性更高,常用于需要更高级别安全保障的场景,比如金融系统等。

  • 密钥 :这是一个只有服务器知道的秘密字符串,就像是 JWT 的 "防伪印章",用于生成签名和验证签名的有效性。密钥的安全性至关重要,一定要妥善保管,不能泄露,否则 JWT 的安全性将无法保证。例如,我们可以设置一个密钥为"my-secret-key-12345"

  • Payload 业务信息 :确定需要包含在 JWT 中的业务数据,如用户 ID、用户名、角色、过期时间等 。这些信息将被编码到 JWT 的 Payload 部分。比如,我们有一个用户,其用户 ID 为123456,用户名为"JohnDoe",角色为"admin",我们希望 JWT 在 1 小时后过期,那么我们可以将这些信息整理成如下格式:

json 复制代码
{
  "userId": 123456,
  "username": "JohnDoe",
  "role": "admin",
  "exp": 1616239022 // 假设这是1小时后的Unix时间戳
}

构建 Header

Header 是 JWT 的 "规则说明" 部分,它是一个 JSON 对象,固定包含两个字段:

  • alg :表示签名算法,我们之前选择了HS256,所以这里填"HS256"

  • typ :表示 Token 类型,固定填"JWT"

    构建好的 Header JSON 对象如下:

json 复制代码
{
  "alg": "HS256",
  "typ": "JWT"
}

然后,我们需要将这个 JSON 对象进行 Base64Url 编码 ,得到一个字符串。Base64Url 编码是一种针对 URL 安全的 Base64 编码方式,它将标准 Base64 编码中的+替换为-/替换为_,并移除填充字符= 。在 JavaScript 中,我们可以使用以下代码进行 Base64Url 编码:

javascript 复制代码
function base64UrlEncode(str) {
  return btoa(unescape(encodeURIComponent(str)))
   .replace(/\+/g, '-')
   .replace(/\//g, '_')
   .replace(/=/g, '');
}
const header = {
  "alg": "HS256",
  "typ": "JWT"
};
const encodedHeader = base64UrlEncode(JSON.stringify(header));
console.log(encodedHeader);

上述代码执行后,encodedHeader的值可能是eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 ,这就是编码后的 Header,它将成为 JWT 的第一部分。

构建 Payload

Payload 是承载业务数据的部分,我们将之前准备好的业务信息整理成 JSON 对象的形式,如下:

json 复制代码
{
  "userId": 123456,
  "username": "JohnDoe",
  "role": "admin",
  "exp": 1616239022
}

这里需要特别注意exp字段,它表示过期时间,是一个 Unix 时间戳,一旦当前时间超过这个时间戳,JWT 就会被视为过期 。同样,我们要对这个 Payload JSON 对象进行 Base64Url 编码,在 JavaScript 中,编码方式和 Header 类似:

javascript 复制代码
const payload = {
  "userId": 123456,
  "username": "JohnDoe",
  "role": "admin",
  "exp": 1616239022
};
const encodedPayload = base64UrlEncode(JSON.stringify(payload));
console.log(encodedPayload);

执行上述代码后,encodedPayload的值可能是eyJ1c2VySWQiOjEyMzQ1NiwidXNlcm5hbWUiOiJKb2huRG9lIiwicm9sZSI6ImFkbWluIiwiZXhwIjoxNjE2MjM5MDIyfQ ,这就是编码后的 Payload,将作为 JWT 的第二部分。

拼接 Header 和 Payload

将编码后的 Header 和 Payload 用点号(.)连接起来,形成一个待签名字符串 。在 JavaScript 中,可以这样实现:

javascript 复制代码
const signedString = encodedHeader + '.' + encodedPayload;
console.log(signedString);

得到的signedString可能是eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEyMzQ1NiwidXNlcm5hbWUiOiJKb2huRG9lIiwicm9sZSI6ImFkbWluIiwiZXhwIjoxNjE2MjM5MDIyfQ ,这个字符串包含了 JWT 的头部和载荷信息,接下来就要对它进行签名,以保证信息的完整性和真实性。

生成 Signature

Signature 是 JWT 防篡改的核心部分,它的生成规则是:用服务器的密钥(比如"my-secret-key-12345")和选定的算法(这里是HS256),对 "待签名字符串" 进行哈希计算,得到二进制签名,然后再将二进制签名转成 Base64URL 编码 。在 JavaScript 中,可以使用crypto模块来实现HS256签名,示例代码如下:

javascript 复制代码
const crypto = require('crypto');
const secret = "my-secret-key-12345";
const hash = crypto.createHmac('sha256', secret)
  .update(signedString)
  .digest('base64');
const signature = hash
  .replace(/\+/g, '-')
  .replace(/\//g, '_')
  .replace(/=/g, '');
console.log(signature);

执行上述代码后,signature的值可能是SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c ,这就是生成的签名,它将成为 JWT 的第三部分。

组装完整 JWT Token

最后,将编码后的 Header、Payload 和 Signature 用点号(.)连接起来,就得到了完整的 JWT Token 。在 JavaScript 中:

javascript 复制代码
const jwtToken = encodedHeader + '.' + encodedPayload + '.' + signature;
console.log(jwtToken);

得到的jwtToken可能是eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEyMzQ1NiwidXNlcm5hbWUiOiJKb2huRG9lIiwicm9sZSI6ImFkbWluIiwiZXhwIjoxNjE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c ,这个字符串就是我们最终生成的 JWT Token,服务器可以将它返回给客户端,客户端在后续的请求中携带这个 Token,服务器通过验证这个 Token 来确认请求的合法性和用户的身份。

JWT 的验证流程

当客户端拿着 JWT Token 来访问受保护资源时,服务器需要对这个 Token 进行验证,以确保请求的合法性和安全性。JWT 的验证流程就像是一个严谨的安检过程,每一个环节都不可或缺,下面我们就详细了解一下这个流程 。

接收 Token

客户端在向服务器发送请求时,会将 JWT Token 放在请求头(Header)的Authorization字段中 ,格式通常为Bearer <token> 。例如:

Plain 复制代码
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

服务器在接收到请求后,首先会从请求头中提取出这个Authorization字段,并从中解析出 JWT Token 。在大多数 Web 开发框架中,都有便捷的方法来获取请求头中的信息。比如在 Node.js 中使用 Express 框架,可以通过req.headers.authorization来获取Authorization字段的值,然后再通过字符串操作提取出真正的 Token 部分 。

拆分 Token

服务器拿到 JWT Token 后,会按点号(.)将其分割成三个部分,分别对应 JWT 的 Header、Payload 和 Signature 。在 JavaScript 中,可以使用split方法来实现:

javascript 复制代码
const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
const parts = token.split('.');
const header = parts[0];
const payload = parts[1];
const signature = parts[2];
console.log(header, payload, signature);

通过上述代码,我们就得到了 JWT 的三个组成部分,接下来就可以分别对它们进行处理和验证 。

解析 Header

对分割得到的 Header 部分进行 Base64Url 解码 ,得到一个 JSON 字符串,再将其解析为 JSON 对象,这样就能获取到 JWT 的元数据信息,特别是签名算法 。在 JavaScript 中,可以使用以下代码实现:

javascript 复制代码
function base64UrlDecode(str) {
  return decodeURIComponent(
    atob(str)
     .split('')
     .map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
     .join('')
  );
}
const decodedHeader = base64UrlDecode(header);
const headerObj = JSON.parse(decodedHeader);
console.log(headerObj.alg); // 输出签名算法,如HS256

通过解析 Header,服务器就知道了应该使用哪种算法来验证签名,比如这里得到的algHS256,就表明要使用 HMAC SHA - 256 算法来进行后续的签名验证 。

解析 Payload 并检查过期时间

同样,对 Payload 部分进行 Base64Url 解码并解析为 JSON 对象 ,这样就能获取到其中包含的业务数据和声明信息 。在 JavaScript 中:

javascript 复制代码
const decodedPayload = base64UrlDecode(payload);
const payloadObj = JSON.parse(decodedPayload);
console.log(payloadObj);

解析出 Payload 后,重点要检查其中的过期时间(exp字段) 。获取当前时间的 Unix 时间戳,与exp字段的值进行对比 。如果当前时间大于exp,说明 JWT 已经过期,服务器应立即拒绝该请求 。例如:

javascript 复制代码
const currentTime = Math.floor(Date.now() / 1000);
if (payloadObj.exp && currentTime > payloadObj.exp) {
  throw new Error('JWT has expired');
}

通过检查过期时间,服务器可以确保只处理有效的 JWT,防止过期的 Token 被使用,保障系统的安全性 。

重新计算签名并对比

这是验证 JWT 是否被篡改的关键步骤 。服务器会使用之前从 Header 中获取的签名算法(如HS256),以及服务器端保存的密钥(和生成 JWT 时使用的密钥相同) ,对编码后的 Header 和 Payload 进行签名计算 。在 JavaScript 中,使用crypto模块来实现HS256签名计算:

javascript 复制代码
const crypto = require('crypto');
const secret = "my-secret-key-12345";
const data = header + '.' + payload;
const hash = crypto.createHmac('sha256', secret)
  .update(data)
  .digest('base64');
const calculatedSignature = hash
  .replace(/\+/g, '-')
  .replace(/\//g, '_')
  .replace(/=/g, '');

计算出签名后,将其与 JWT 中携带的签名(之前拆分得到的signature)进行对比 。如果两者一致,说明 JWT 在传输过程中没有被篡改,是可信的;如果不一致,那就意味着 JWT 可能被恶意修改过,服务器会拒绝这个请求 。例如:

javascript 复制代码
if (calculatedSignature!== signature) {
  throw new Error('JWT signature is invalid');
}

通过这一系列严格的验证步骤,服务器就能准确判断 JWT 的有效性和完整性,确保只有合法的请求才能访问受保护的资源 。

JWT 的防篡改原理

JWT 的防篡改能力是保障其在网络传输中数据安全的关键特性,而这一特性的核心就在于 Signature(签名)部分 。我们知道,JWT 由 Header(头部)、Payload(载荷)和 Signature 三部分组成,其中 Header 和 Payload 在生成 JWT 时都会进行 Base64Url 编码,然后通过点号(.)连接起来,形成一个待签名字符串 。而 Signature 就是使用在 Header 中指定的签名算法(如HS256RS256等 ),以及一个只有服务器知道的密钥(Secret) ,对待签名字符串进行签名计算得到的结果。

HS256算法为例,签名的生成公式为:signature = HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret) 。这个签名就像是 JWT 的 "数字指纹",它是根据 Header 和 Payload 的内容以及密钥计算出来的,具有唯一性和不可伪造性 。当服务器收到 JWT 后,会按照同样的算法和密钥,重新计算 Header 和 Payload 的签名 。如果重新计算得到的签名与 JWT 中携带的签名一致,那就说明 JWT 在传输过程中没有被篡改,因为如果有人试图修改 Header 或 Payload 中的任何内容,哪怕只是一个字符,重新计算出来的签名都会发生巨大的变化 。

例如,假设我们有一个原始的 JWT,其 Header 部分为{"alg": "HS256", "typ": "JWT"} ,经过 Base64Url 编码后得到eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 ;Payload 部分为{"sub": "123456", "name": "JohnDoe", "iat": 1616239022} ,编码后是eyJzdWIiOiIxMjM0NTYifQ 。服务器使用密钥"my-secret-key" ,通过HS256算法计算签名,得到签名部分xxxxxx ,最终完整的 JWT 为eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTYifQ.xxxxxx 。现在,假设黑客试图篡改 Payload 中的sub字段,将其改为"999999" ,然后重新编码 Payload 得到eyJzdWIiOiI5OTk5OTkiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE2MTYyMzkwMjJ9 ,并使用原来的签名xxxxxx 构造一个假的 JWT:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5OTk5OTkiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE2MTYyMzkwMjJ9.xxxxxx 。当服务器收到这个假的 JWT 后,会用同样的密钥和算法重新计算签名,由于 Payload 已经被篡改,所以计算出来的新签名与原来的xxxxxx 肯定不一致,服务器就能立刻判断出这个 JWT 是被篡改过的,从而拒绝该请求 。

正是因为签名与 Header 和 Payload 的内容紧密相关,并且密钥只有服务器知晓,黑客即使获取到 JWT,也无法在不知道密钥的情况下伪造出合法的签名 ,所以 JWT 能够有效地防止被篡改,确保了数据在传输过程中的完整性和真实性 。

实际应用案例与代码示例

案例场景介绍

假设我们正在开发一个在线商城系统,用户在登录成功后,需要获取一个 JWT Token,用于后续访问商城的各种受保护资源,比如查看订单列表、管理收货地址等 。具体流程如下:

  1. 用户登录:用户在商城的登录页面输入用户名和密码,点击登录按钮,向服务器发送登录请求 。

  2. 服务器验证:服务器接收到登录请求后,验证用户名和密码是否正确 。如果验证通过,进入下一步;如果验证失败,返回错误信息,提示用户重新登录 。

  3. 生成 JWT Token :服务器验证用户身份成功后,根据用户的信息(如用户 ID、用户名、角色等 )生成一个 JWT Token 。例如,用户 ID 为123456,用户名为"JohnDoe",角色为"customer" ,服务器设置 JWT Token 的过期时间为 1 小时 。

  4. 返回 Token:服务器将生成的 JWT Token 返回给客户端,客户端可以将其存储在本地,比如存储在浏览器的 Local Storage 中,或者移动应用的本地存储中 。

  5. 访问受保护资源:当用户需要访问商城的受保护资源时,比如查看订单列表,客户端会在请求头中携带之前获取的 JWT Token,向服务器发送请求 。

  6. 服务器验证 Token:服务器接收到请求后,从请求头中提取 JWT Token,并按照之前介绍的验证流程进行验证 。如果验证通过,服务器允许用户访问受保护资源,返回订单列表数据;如果验证失败,服务器返回错误信息,提示用户重新登录或者 Token 无效 。

代码实现(以 Node.js 为例)

在 Node.js 中,我们可以使用jsonwebtoken库来方便地生成和验证 JWT 。首先,需要安装jsonwebtoken库,在项目目录下执行以下命令:

bash 复制代码
npm install jsonwebtoken

安装完成后,我们可以编写以下代码来实现上述案例场景:

javascript 复制代码
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();
app.use(express.json());

// 模拟用户数据库
const users = [
  { id: 123456, username: 'JohnDoe', password: 'password123', role: 'customer' }
];

// 登录路由,生成JWT
app.post('/login', (req, res) => {
  const { username, password } = req.body;
  // 查找用户
  const user = users.find(u => u.username === username && u.password === password);
  if (!user) {
    return res.status(401).json({ error: '用户名或密码错误' });
  }
  // 生成JWT Payload
  const payload = {
    userId: user.id,
    username: user.username,
    role: user.role
  };
  const secretKey = 'your-secret-key'; // 请替换为实际的密钥
  const options = { expiresIn: '1h' }; // 设置过期时间为1小时
  const token = jwt.sign(payload, secretKey, options);
  res.json({ token });
});

// 受保护的订单列表路由,需要JWT验证
app.get('/orders', (req, res, next) => {
  const token = req.headers.authorization;
  if (!token) {
    return res.status(401).send('请先登录');
  }
  const secretKey = 'your-secret-key';
  try {
    const decoded = jwt.verify(token, secretKey);
    // 这里可以根据decoded中的用户信息进行权限验证等操作
    // 假设验证通过,返回订单列表数据
    const orders = [
      { id: 1, product: '商品1', amount: 2 },
      { id: 2, product: '商品2', amount: 1 }
    ];
    res.json({ orders });
  } catch (error) {
    res.status(403).send('无效的Token');
  }
});

const port = 3000;
app.listen(port, () => {
  console.log(`服务器运行在端口 ${port}`);
});

在上述代码中:

  • /login路由用于处理用户登录请求,验证用户名和密码后,使用jwt.sign方法生成 JWT Token 并返回给客户端 。jwt.sign方法接收三个参数:payload(包含用户信息的对象)、secretKey(密钥)和options(可选参数,这里设置了过期时间) 。

  • /orders路由是受保护的资源路由,首先从请求头中获取Authorization字段,提取 JWT Token 。然后使用jwt.verify方法验证 Token 的有效性 。jwt.verify方法接收两个参数:token(要验证的 JWT Token)和secretKey(密钥) 。如果验证成功,decoded将包含 JWT Payload 中的用户信息,我们可以根据这些信息进行后续的业务处理,比如返回订单列表数据;如果验证失败,会抛出异常,捕获异常后返回错误信息 。

总结与拓展

通过前面的内容,我们已经全面掌握了 JWT 的生成、验证和防篡改机制。从生成过程来看,确定算法、密钥和 Payload 业务信息是基础,构建 Header 和 Payload 并进行 Base64Url 编码,再拼接两者生成待签名字符串,最后使用密钥和算法生成签名,组装成完整的 JWT Token,每一步都紧密相连,缺一不可。验证流程则是对生成过程的反向检查,通过拆分 Token、解析 Header 和 Payload,检查过期时间并重新计算签名进行对比,确保 JWT 的有效性和合法性。而 JWT 的防篡改原理,依赖于签名与 Header、Payload 以及密钥的紧密关联,只要密钥不泄露,签名就无法被伪造,保证了数据在传输过程中的完整性和真实性 。

在实际应用 JWT 时,还有一些注意事项。首先,密钥的管理至关重要,一定要妥善保管,避免泄露,建议通过环境变量、配置中心或密钥管理服务(KMS)来管理密钥。其次,JWT 的过期时间应设置得合理,不宜过长也不宜过短,过长会增加安全风险,过短则可能导致用户频繁登录,影响用户体验。对于需要长期保持登录的应用,可以配合刷新令牌(Refresh Token)机制来获取新的 JWT 。另外,由于 JWT 的 Payload 是 Base64Url 编码而非加密,所以不要在其中存放敏感信息,如用户密码等。

随着技术的不断发展,JWT 在未来的应用场景也会更加广泛和深入。在分布式系统和微服务架构中,JWT 的无状态特性将使其成为身份验证和授权的首选方案之一,能够更好地实现系统间的通信和协作。同时,JWT 也可能会与其他安全技术相结合,如多因素认证(MFA)等,进一步提升系统的安全性 。希望大家在实际项目中能够灵活运用 JWT,不断探索其更多的可能性,为应用的安全和稳定保驾护航。如果对 JWT 还有更多的疑问或者想要深入研究,可以查阅相关的文档和资料,进行更多的实践和尝试。

相关推荐
chaors4 小时前
从零学RAG0x05实战应用:企业智能知识库
人工智能·github·ai编程
lauo7 小时前
dtnsbot分身网页版正式上线:开启“灵魂与肉身分离”的智能体远程控制新纪元
人工智能·智能手机·架构·开源·github
国产化创客9 小时前
OpenClaw在树莓派全流程安装部署
linux·人工智能·github·agi
Java后端的Ai之路9 小时前
CLI 与 GitHub CLI 完整教程
github·cli·远程仓库·github cli
badhope10 小时前
GitHub热门AI技能Top20实战指南
前端·javascript·人工智能·git·python·github·电脑
m0_6356474812 小时前
git管理github上的repository(三)
git·github
CoderJia程序员甲12 小时前
GitHub 热榜项目 - 日榜(2026-03-13)
ai·大模型·llm·github·ai教程
研究点啥好呢13 小时前
3月13日GitHub热门项目推荐 | AI代理的安全思考
人工智能·安全·网络安全·ai·github·openclaw