Skip to content

Json Web Token (JWT)

JSON Web Token(JWT),又称为JSON令牌,是一种用于在网络应用之间安全地传输信息的开放标准(RFC 7519)。它采用了一种紧凑的、自包含的方式来表示信息,通常用于身份验证和授权。JWT的设计目标是确保信息的完整性和安全性,同时具备易于使用和传输的特点。

JWT的结构

JWT的结构由以下三部分组成:

1. Header(头部)

包含了关于令牌的元数据和描述,通常包括令牌的类型(typ)和签名算法(alg)等信息。这一部分是一个JSON对象,通常会被base64url编码。

json
// Header:
{
  "alg": "HS256",
  "typ": "JWT"
}

2. Payload(载荷)

包含了需要传输的数据,也是一个JSON对象,通常包括一些声明(claim)和用户定义的数据。这一部分是一个JSON对象。通常会被base64url编码。

常见的声明有:

  • iss(Issuer):令牌的发行者。
  • sub(Subject):令牌的主题,通常是用户的唯一标识符。
  • aud(Audience):令牌的受众,表示该令牌针对哪些接收者。
  • iat(Issued At):令牌的颁发时间。
  • exp(Expiration Time):令牌的过期时间。
  • nbf(Not Before):令牌的生效时间。
  • jti(JWT ID):令牌的唯一标识符。

除了标准声明,你还可以在Payload中添加自定义的数据。

json
// Payload:
{
  "iss": "you_name",
  "sub": "id_abcdefghimg",
  "iat": 1737620000,
  "exp": 1737620000 + 3600,
  "username": "大白菜",
  "role": "admin"
}

3. Signature(签名)

用于验证JWT的真实性和完整性。签名的生成方式通常是将Header和Payload部分组合起来,使用一个密钥(secret key)进行哈希运算,然后再与令牌中的签名部分比对。这个部分确保了令牌在传输过程中没有被篡改。

js
// .env
secret_key = "自定义secret_key";

TIP

确保这个密钥在你的应用中安全保存,不要硬编码在代码中,特别是在生产环境中。可以使用环境变量或配置文件来管理密钥。

JWT的工作流程

JWT的工作流程通常涉及三个主要角色:颁发者(Issuer)用户(User)验证者(Verifier)

  • 颁发者(Issuer):颁发者是负责创建JWT的实体。颁发者将用户的信息和一些声明以及一个签名加工在一起,生成一个JWT,并将其发送给用户。

  • 用户(User):用户是JWT的持有者,通常是一个需要在不同应用之间传递信息的实体。用户可以在需要的时候将JWT发送给不同的应用来进行身份验证或授权。

  • 验证者(Verifier):验证者是负责验证JWT的实体。它们接收到JWT后,首先会解析JWT的Header和Payload,然后使用事先共享的密钥来验证Signature的有效性。如果验证成功,验证者可以信任JWT中包含的信息。

JWT的工作流程如下

  1. 用户通过某种方式(例如用户名密码登录)向颁发者请求令牌。
  2. 颁发者验证用户的身份后,创建一个JWT,包含用户的信息和一些声明,然后使用自己的私钥来签名JWT。
  3. 颁发者将JWT发送给用户
  4. 用户在与不同的应用通信时,可以将JWT发送给应用作为身份验证或授权凭证。
  5. 应用接收到JWT后,使用之前与颁发者共享的公钥来验证JWT的签名,确保JWT没有被篡改。
  6. 如果JWT验证通过,应用可以信任其中的信息,并根据需要执行相应的操作。

JWT的优点

JWT在现代应用程序中广泛使用,因为它具有多个优点:

  • 轻量级和自包含性:JWT是紧凑的文本格式,易于传输和解析。所有必要的信息都包含在JWT本身中,无需在服务器上保留会话状态。
  • 分布式身份验证:JWT使得分布式系统中的身份验证变得更加简单,因为不同的应用可以共享相同的JWT颁发者,而无需在各自的数据库中存储用户凭据。
  • 无状态:由于JWT本身包含了所有必要的信息,服务器不需要维护会话状态,这对于负载均衡和容错性很有帮助。
  • 可扩展性:JWT的Payload可以包含自定义声明,可以根据应用的需求添加额外的信息。
  • 安全性:JWT使用签名来保护其完整性,防止篡改。使用适当的算法和密钥可以确保JWT的安全性。

使用场景

JWT通常用于以下场景:

  • 身份验证:用户登录后,颁发者可以生成一个包含用户信息的JWT,用户可以在请求中携带该JWT,以证明其身份。

  • 授权:应用可以使用JWT来授权用户访问某些资源或执行特定操作。JWT的Payload可以包 含用户的角色和权限信息。

  • 单点登录(SSO):JWT可以用于实现单点登录,用户只需登录一次,就可以访问多个关联的应用。

  • 密码重置:JWT可以用于生成包含密码重置信息的令牌,用户可以使用该令牌来重置其密码。

  • 信息交换:JWT可以用于不同应用之间安全地交换信息,例如在微服务架构中。

安全考虑

虽然JWT在许多场景下非常有用,但也需要谨慎使用以确保安全性:

  • 密钥管理:密钥的安全管理是关键。泄漏密钥会导致令牌被伪造,因此需要采用适当的密钥管理措施,如定期轮换密钥。
  • 过期时间:JWT通常包含了过期时间(exp)声明,应用需要定期检查令牌的有效性,并确保不使用已过期的令牌。
  • 非对称加密:对于高度敏感的信息,可以考虑使用非对称加密算法,以提高安全性。在这种情况下,验证者使用颁发者的公钥来验证签名。
  • 避免在令牌中存储敏感信息:尽量避免在JWT的Payload中存储敏感信息,因为Payload部分是Base64编码的,可能会被解码。
  • 使用HTTPS:JWT在传输过程中可能会被截获,因此建议在使用JWT时始终使用HTTPS来确保通信的安全性。

示例

js
// 需要安装jsonwebtoken依赖
const jwt = require('jsonwebtoken');

// 定义私钥
const secretKey = "your_private_key"
// 定义头部
const header = { alg: 'HS256', typ: 'JWT' };
// 定义载荷
const payload = {
  "iss": "you_name",
  "sub": "id_abcdefghimg",
  "iat": 1737620000,
  "exp": 1737620000 + 3600,
  "username": "大白菜",
  "role": "admin"
};

// 生成JWT
const token = jwt.sign({ header, payload }, secretKey, { algorithm: 'HS256' });
console.log("出书token:", token);

// 验证JWT
jwt.verify(token, secretKey, (err, decoded) => {
  if (err) {
    console.log('身份验证失败');
  } else {
    console.log('身份验证成功');
  }
});
rust
// 需要安装 jsonwebtoken 、 serde 和 serde_json 依赖

use serde::{Deserialize, Serialize};
use jsonwebtoken::{encode, decode, Header, Validation, EncodingKey, DecodingKey};


// 定义私钥
let secret_key  = 'your_private_key'.as_bytes();

// 定义载荷结构
#[derive(Debug, Serialize, Deserialize)]
struct Claims {
    iss:String,
    sub: String,
    iat: u64,
    exp: u64,
    username: String,
    role: String,
}
// 当前时间的时间戳,用于生成token的时间
let issued_at = SystemTime::now()
    .duration_since(UNIX_EPOCH)
    .unwrap()
    .as_secs();
// 创建一个载荷
let claims_set = Claims {
    iss: "you_name".to_owned(),
    sub: "id_abcdefghimg".to_owned(),
    iat: issued_at,
    exp: issued_at + 3600, // token有效期为1小时(秒)
    username: "大白菜".to_owned(),
    role: "admin".to_owned(),
};

// 生成JWT
let token = encode(&Header::default(), &claims_set, &EncodingKey::from_secret(secret_key)).unwrap();
println!("Token: {}", token);


// 验证JWT
let data = decode::<Claims>(&token, &DecodingKey::from_secret(&secret_key), &&Validation::default());
match data {
    Ok(token_data) => {
        println!("打印解码后的claims: {:?}", token_data.claims);
    },
    Err(err) => {
        println!("解码token出错: {:?}", err);
    }
}

结论

JSON Web Token(JWT)是一种广泛用于身份验证和授权的标准,它具有轻量级、自包含、分布式、无状态、可扩展等优点,适用于多种应用场景。然而,使用JWT时需要注意密钥管理、安全性和合适的过期时间等方面,以确保应用的安全性。

JWT在现代应用程序中扮演着重要的角色,为开发人员提供了一种灵活且安全的方式来传输信息和验证用户身份。它已成为许多Web应用、移动应用和API的标准身份验证方法之一,可以帮助开发人员构建更安全、更灵活的应用程序。

个人收集整理, MIT License