跳到主要内容
ecdsa.com
Rust

jsonwebtoken (Rust)

Vincent Prouillet 开发的 jsonwebtoken crate,Rust 中使用最广的 JWT 库:Algorithm 是封闭枚举,没有 none;exp 为必需;默认容差 60 秒;而且从第 10 版起,必须自行选择密码学后端。
许可证
MIT
检查的版本
11.1.0 ·
源代码
github.com/Keats/jsonwebtoken
文档
docs.rs/jsonwebtoken/11.1.0/jsonwebtoken/

兼容性概览

JOSE 与 JWT

JWS 算法
HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384EdDSA

jsonwebtoken 通过 encode、decode 和 Validation 对象编码和解码 JWT,声明的序列化由 serde 完成。从第 10 版起,密码学运算由通过特性(feature)选择的后端提供——aws_lc_rs 或 rust_crypto——本次检查使用的是 aws_lc_rs。忘记启用该特性不会导致构建失败:只启用默认特性时,11.1.0 能够编译,但在第一次调用 encode() 时 panic,报错 Could not automatically determine the process-level CryptoProvider。应像示例的清单文件那样,恰好启用一个后端。

算法集合是一个封闭枚举:256/384/512 的 HS、RS 和 PS,以及 ES256、ES384 和 EdDSA 的签名与验证均成功,而 ES512、ES256K 和 Ed25519 根本不是枚举变体。也没有 none 变体,因此未签名的令牌在解析头部时就会失败,报错 unknown variant none。Validation::new(alg) 就是允许列表:用 Validation::new(ES256) 检查 HS256 令牌,报错 InvalidAlgorithm;即使两种算法都允许,以 EC 公钥的 PEM 文本为密钥的 HS256 令牌也会报错 InvalidKeyFormat,因为 EC DecodingKey 不能充当 HMAC 密钥。

声明检查比大多数库更严格:不含 exp 的令牌会报错 Missing required claim: exp;默认容差为 60 秒——57 秒前过期的令牌仍然验证通过。应像示例那样调小 leeway,并在 Validation 上设置颁发者和受众。ES256 在签名时会拒绝 P-384 密钥,报错 InvalidEcdsaKey。

ES256 签名是 JWS 要求的 64 字节原始 r‖s,DER 签名会报错 InvalidSignature。密钥可以从 PEM(from_ec_pem、from_rsa_pem、from_ed_pem)和 DER 加载;对于 Ed25519 的 DER,编码密钥接收 PKCS#8,解码密钥接收 32 字节的原始公钥。可以用 JWT 调试器检查令牌,用 JWT 密钥检测工具测试 HMAC 密钥。

JWT 以外的签名,可以直接使用后端 crate:aws-lc-rs 或 RustCrypto ecdsa。

事实及其依据的检查

以下内容均非抄自文档。检查脚本 content/libraries/verify/jsonwebtoken-rust/run.sh 于2026年10月20日在容器镜像 rust:1.99.1-trixie 中运行了 jsonwebtoken (Rust) 11.1.0;本页内容必须与它的输出一致,每条事实都列出了对应的输出行。

  • JWS 算法

    HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384EdDSA

    256/384/512 的 HS、RS 和 PS,以及 ES256、ES384 和 EdDSA 的签名与验证均成功;ES512、ES256K 和 Ed25519 不是 Algorithm 的变体。

    检查记录
    fact jws-algorithms = HS256, HS384, HS512, RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, EdDSA
    evidence jws-algorithms: ES512: not an Algorithm variant
    evidence jws-algorithms: ES256K: not an Algorithm variant
    evidence jws-algorithms: Ed25519: not an Algorithm variant
  • ES256 签名编码

    raw

    ES256 签名是 64 字节的原始 r‖s。

    检查记录
    fact jws-ecdsa-encoding = raw
  • JWS 中的 DER 签名

    rejected

    DER 编码的 ES256 签名会报错 InvalidSignature。

    检查记录
    fact jws-der-signature = rejected
    evidence jws-der-signature: Err("InvalidSignature")
  • 算法允许列表

    required

    Validation::new(alg) 设定允许的算法;用 Validation::new(ES256) 检查 HS256 令牌,报错 InvalidAlgorithm。

    检查记录
    fact jwt-algorithm-allowlist = required
    evidence jwt-algorithm-allowlist: HS256 token with Validation::new(ES256): Err("InvalidAlgorithm")
  • 未签名的令牌(alg none)

    rejected

    none 不是 Algorithm 的变体:解析头部时报错 unknown variant none。

    检查记录
    fact jwt-alg-none = rejected
    evidence jwt-alg-none: Err("JSON error: unknown variant `none`, expected one of `HS256`, `HS384`, `HS512`, `ES256`, `ES384`, `RS256`, `RS384`, `RS512`, `PS256`, `PS384`, `PS512`, `EdDSA` at line 1 column 13"); "none" parses as Algorithm: false
  • 把公钥用作 HMAC 密钥

    rejected

    在同时允许 ES256 和 HS256 时,以 PEM 文本为密钥的 HS256 令牌用 EC DecodingKey 验证,报错 InvalidKeyFormat。

    检查记录
    fact jwt-hmac-public-key = rejected
    evidence jwt-hmac-public-key: algorithms [ES256, HS256], EC DecodingKey: Err("InvalidKeyFormat")
  • 按 alg 检查曲线

    enforced

    用 P-384 密钥签名 ES256 时报错 InvalidEcdsaKey。

    检查记录
    fact jwt-ecdsa-curve-check = enforced
    evidence jwt-ecdsa-curve-check: Ok(Err("InvalidEcdsaKey"))
  • 默认时钟偏差

    60s

    Validation::new 把 leeway 设为 60 秒:57 秒前过期的令牌验证通过,63 秒前过期的则未通过。

    检查记录
    fact jwt-clock-skew = 60s
    evidence jwt-clock-skew: Validation::new(HS256).leeway = 60
  • 是否要求过期时间声明

    yes

    不含 exp 的令牌会报错 Missing required claim: exp。

    检查记录
    fact jwt-exp-required = yes
    evidence jwt-exp-required: Err("Missing required claim: exp")
  • 未选择密码学后端

    runtime-panic

    aws_lc_rs 和 rust_crypto 都未启用时,crate 能够编译,但第一次调用 encode() 时 panic,报错 Could not automatically determine the process-level CryptoProvider from jsonwebtoken crate features.

    检查记录
    fact crypto-provider-without-feature = runtime-panic
    evidence crypto-provider-without-feature: default features compile; the first encode() panics with: Could not automatically determine the process-level CryptoProvider from jsonwebtoken crate features.

用法

签发 HS256 令牌,并显式设置算法、颁发者和 30 秒容差来验证它。
use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation};
use serde::{Deserialize, Serialize};
use std::time::{SystemTime, UNIX_EPOCH};

#[derive(Serialize, Deserialize)]
struct Claims {
    sub: String,
    iss: String,
    exp: u64,
}

fn main() {
    // Choose a backend explicitly: features = ["aws_lc_rs"] or ["rust_crypto"].
    let secret = b"use at least 32 random bytes from a secrets manager";
    let exp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() + 600;
    let claims = Claims { sub: "user-42".into(), iss: "https://auth.example.com".into(), exp };
    let token = encode(&Header::new(Algorithm::HS256), &claims, &EncodingKey::from_secret(secret)).unwrap();

    // Validation::new(alg) is the allow-list; exp is required, leeway defaults to 60 s.
    let mut validation = Validation::new(Algorithm::HS256);
    validation.set_issuer(&["https://auth.example.com"]);
    validation.leeway = 30;
    let data = decode::<Claims>(&token, &DecodingKey::from_secret(secret), &validation).unwrap();
    println!("sub: {}", data.claims.sub);
}

代码片段测试工具会在容器镜像 rust:1.99.1-trixie 中原样运行每个示例,只要输出不匹配,运行就会失败。

命令
cargo run --quiet --release
输出必须匹配(正则表达式)
sub: user-42

库