Rust JWT处理库jwt-compact的使用,提供轻量高效的JSON Web Token生成与验证功能

Rust JWT处理库jwt-compact的使用,提供轻量高效的JSON Web Token生成与验证功能

jwt-compact是一个专注于类型安全和安全加密原语的轻量级JSON Web Token(JWT)实现库。

基本用法

首先在Cargo.toml中添加依赖:

[dependencies]
jwt-compact = "0.8.0"

基本令牌生命周期示例

以下是内容中提供的基本令牌生命周期示例:

use chrono::{Duration, Utc};
use jwt_compact::{prelude::*, alg::{Hs256, Hs256Key}};
use serde::{Serialize, Deserialize};

/// 自定义令牌中的声明
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct CustomClaims {
    #[serde(rename = "sub")]
    subject: String,
    // 其他字段...
}

// 选择令牌创建/验证的时间相关选项
let time_options = TimeOptions::default();
// 创建一个对称HMAC密钥,将用于创建和验证令牌
let key = Hs256Key::new(b"super_secret_key_donut_steel");
// 创建一个令牌
let header = Header::empty().with_key_id("my-key");
let claims = Claims::new(CustomClaims { subject: "alice".to_owned() })
    .set_duration_and_issuance(&time_options, Duration::hours(1))
    .set_not_before(Utc::now());
let token_string = Hs256.token(&header, &claims, &key)?;
println!("token: {token_string}");

// 解析令牌
let token = UntrustedToken::new(&token_string)?;
// 在验证令牌之前,我们可以使用`Header.key_id`字段找到签署令牌的密钥
assert_eq!(token.header().key_id.as_deref(), Some("my-key");
// 验证令牌完整性
let token: Token<CustomClaims> = Hs256.validator(&key).validate(&token)?;
// 验证附加条件
token.claims()
    .validate_expiration(&time_options)?
    .validate_maturity(&time_options)?;
Ok::<_, anyhow::Error>(())

完整示例代码

下面是一个更完整的JWT生成与验证示例:

use chrono::{Duration, Utc};
use jwt_compact::{prelude::*, alg::{Hs256, Hs256Key}};
use serde::{Serialize, Deserialize};
use anyhow::Result;

#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct CustomClaims {
    #[serde(rename = "sub")]
    subject: String,
    #[serde(rename = "role")]
    user_role: String,
    #[serde(rename = "exp")]
    expiration: Option<i64>,
}

fn main() -> Result<()> {
    // 1. 创建令牌
    let token = create_jwt_token()?;
    println!("Generated token: {}", token);
    
    // 2. 验证令牌
    validate_jwt_token(&token)?;
    println!("Token validated successfully!");
    
    Ok(())
}

fn create_jwt_token() -> Result<String> {
    // 时间选项
    let time_options = TimeOptions::default();
    
    // 创建HMAC密钥
    let key = Hs256Key::new(b"super_secret_key_donut_steel");
    
    // 创建令牌头
    let header = Header::empty()
        .with_key_id("user-auth-key")
        .with_algorithm("HS256");
    
    // 创建自定义声明
    let custom_claims = CustomClaims {
        subject: "user123".to_owned(),
        user_role: "admin".to_owned(),
        expiration: None, // 将由set_duration_and_issuance设置
    };
    
    // 创建并配置Claims
    let claims = Claims::new(custom_claims)
        .set_duration_and_issuance(&time_options, Duration::hours(1))
        .set_not_before(Utc::now());
    
    // 生成令牌字符串
    Hs256.token(&header, &claims, &key).map_err(Into::into)
}

fn validate_jwt_token(token_str: &str) -> Result<()> {
    // 时间选项
    let time_options = TimeOptions::default();
    
    // 使用相同的HMAC密钥
    let key = Hs256Key::new(b"super_secret_key_donut_steel");
    
    // 解析未经验证的令牌
    let untrusted_token = UntrustedToken::new(token_str)?;
    
    // 验证令牌签名
    let token: Token<CustomClaims> = Hs256.validator(&key).validate(&untrusted_token)?;
    
    // 验证时间相关声明
    token.claims()
        .validate_expiration(&time_options)?
        .validate_maturity(&time_options)?;
    
    // 验证自定义声明
    let claims = token.claims();
    println!("Subject: {}", claims.custom.subject);
    println!("Role: {}", claims.custom.user_role);
    
    Ok(())
}

特性

  • 算法特定的签名和验证密钥(即类型安全)
  • 来自RFC 7518的密钥强度要求通过包装类型表达
  • 易于扩展以支持新的签名算法
  • 支持更紧凑的CBOR编码声明
  • 基本的JWK功能,用于从人类可读格式(JSON/YAML/TOML)转换密钥和计算密钥指纹
  • 通过纯Rust sha2 crate实现HS256HS384HS512算法
  • 支持Ed25519椭圆曲线的EdDSA算法和secp256k1椭圆曲线的ES256K算法
  • 通过纯Rust p256 crate支持ES256算法
  • 通过纯Rust rsa crate支持RSA算法(RS*PS*)
  • 支持no_std模式

替代方案

根据用例不同,jsonwebtokenfrank_jwtbiscuit可能是可行的替代方案(例如它们似乎都没有实现EdDSAES256K算法)。


1 回复

Rust JWT处理库jwt-compact使用指南

jwt-compact是一个轻量级、高效的Rust库,用于生成和验证JSON Web Tokens(JWT)。它专注于简单性和性能,同时提供必要的安全功能。

主要特性

  • 轻量级实现,无多余依赖
  • 支持HS256, HS384, HS512签名算法
  • 支持ES256, ES384, ES512签名算法
  • 支持RS256, RS384, RS512签名算法
  • 支持自定义声明验证
  • 时间验证(exp, nbf, iat)
  • 无标准库支持(no_std)

安装

在Cargo.toml中添加依赖:

[dependencies]
jwt-compact = "0.5"

基本用法示例

生成Token示例

use jwt_compact::{alg::Hs256, AlgorithmExt, Claims, Header, TimeOptions, Token};
use serde::{Deserialize, Serialize};

// 自定义声明结构体
#[derive(Debug, Serialize, Deserialize)]
pub struct CustomClaims {
    pub is_admin: bool,
    pub user_id: String,
}

fn main() {
    // 创建HS256算法的签名密钥
    let key = Hs256.generate_key();
    
    // 创建时间选项
    let time_opts = TimeOptions::default();
    
    // 创建自定义声明数据
    let my_claims = CustomClaims {
        is_admin: true,
        user_id: "12345".to_owned(),
    };
    
    // 创建JWT声明,设置7天有效期
    let claims = Claims::new(my_claims)
        .set_duration_and_issuance(&time_opts, chrono::Duration::days(7));
    
    // 生成token
    let header = Header::empty().with_token_type("JWT");
    let token = Hs256.token(header, &claims, &key).unwrap();
    
    println!("生成的Token: {}", token);
}

验证Token示例

use jwt_compact::{alg::Hs256, AlgorithmExt, Validation, UntrustedToken};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub struct CustomClaims {
    pub is_admin: bool,
    pub user_id: String,
}

fn main() {
    // 假设从客户端接收到的token字符串
    let token_str = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...";
    
    // 使用与生成时相同的密钥
    let key = Hs256.generate_key();
    
    // 解析未验证的token
    let untrusted_token = UntrustedToken::new(&token_str).unwrap();
    
    // 创建验证器
    let validation = Validation::default();
    
    // 验证token完整性
    let token: Token<CustomClaims> = Hs256.validate_integrity(&untrusted_token, &key, &validation)
        .unwrap();
    
    // 获取并打印声明信息
    let claims = token.claims();
    println!("用户ID: {}", claims.custom.user_id);
    println!("管理员权限: {}", claims.custom.is_admin);
    println!("过期时间: {:?}", claims.expiration);
}

完整示例代码

以下是一个完整的JWT生成和验证流程示例:

use jwt_compact::{alg::Hs256, AlgorithmExt, Claims, Header, TimeOptions, Token, UntrustedToken, Validation};
use serde::{Deserialize, Serialize};
use chrono::{Duration, Utc};

// 自定义声明结构体
#[derive(Debug, Serialize, Deserialize)]
struct UserClaims {
    user_id: u64,
    username: String,
    roles: Vec<String>,
}

fn main() {
    // 1. 生成JWT Token
    
    // 创建HS256密钥
    let key = Hs256.generate_key();
    
    // 创建时间选项
    let time_opts = TimeOptions::new(Utc::now);
    
    // 创建用户声明
    let user_claims = UserClaims {
        user_id: 42,
        username: "john_doe".to_string(),
        roles: vec!["admin".to_string(), "user".to_string()],
    };
    
    // 构建JWT声明,设置1小时有效期
    let claims = Claims::new(user_claims)
        .set_duration_and_issuance(&time_opts, Duration::hours(1));
    
    // 生成Token
    let header = Header::empty().with_token_type("JWT");
    let token = Hs256.token(header, &claims, &key).unwrap();
    println!("生成的JWT Token:\n{}\n", token);
    
    // 2. 验证JWT Token
    
    // 将Token转换为字符串形式(模拟传输)
    let token_str = token.to_string();
    
    // 解析未验证的Token
    let untrusted_token = UntrustedToken::new(&token_str).unwrap();
    
    // 创建自定义验证规则
    let mut validation = Validation::default();
    validation.required_claims.remove("exp"); // 可选:不强制要求过期时间
    
    // 验证Token
    let verified_token: Token<UserClaims> = Hs256
        .validate_integrity(&untrusted_token, &key, &validation)
        .unwrap();
    
    // 获取验证后的声明
    let verified_claims = verified_token.claims();
    println!("验证后的用户声明:");
    println!("用户ID: {}", verified_claims.custom.user_id);
    println!("用户名: {}", verified_claims.custom.username);
    println!("角色: {:?}", verified_claims.custom.roles);
    println!("签发时间: {:?}", verified_claims.issued_at);
    println!("过期时间: {:?}", verified_claims.expiration);
}

高级用法示例

自定义验证规则

use jwt_compact::{Validation, ValidationError};

// 创建自定义验证器
let mut validation = Validation::default();
validation.required_claims.remove("exp"); // 不要求过期时间

// 添加自定义验证逻辑
validation.invalidate_if = Some(Box::new(|claims: &UserClaims| {
    // 检查用户是否有admin角色
    if !claims.roles.contains(&"admin".to_string()) {
        Err(ValidationError::new("需要管理员权限"))
    } else {
        Ok(())
    }
}));

使用ES256算法示例

use jwt_compact::{alg::Es256, AlgorithmExt};
use p256::ecdsa::SigningKey;
use rand::thread_rng;

// 生成ES256密钥对
let signing_key = SigningKey::random(&mut thread_rng());
let verifying_key = signing_key.verifying_key();

// 创建用户声明
let claims = Claims::new(UserClaims {
    user_id: 1,
    username: "admin".to_string(),
    roles: vec!["super_admin".to_string()],
});

// 使用ES256算法生成Token
let token = Es256.token(Header::default(), &claims, &signing_key).unwrap();

// 验证Token
let untrusted_token = UntrustedToken::new(&token).unwrap();
let _verified_token = Es256.validate_integrity(&untrusted_token, &verifying_key, &Validation::default())
    .unwrap();

性能建议

  1. 对于对称加密(HS*),可以缓存密钥生成结果
  2. 对于非对称加密(RS*, ES*),可以缓存公钥验证对象
  3. 重用Validation对象而不是每次都创建新的

注意事项

  • 确保妥善保管签名密钥
  • 合理设置token过期时间
  • 验证所有必要的声明
  • 在生产环境中使用强加密算法(如RS256或ES256而非HS256)
回到顶部