#jwt #token #jwk #web #api-token #web-api #rsa-key

jsonwebtoken-rustcrypto

使用 RustCrypto 项目中的加密原语,以强类型方式创建和解码 JWT

3 个稳定版本

1.2.0 2023 年 4 月 13 日
1.1.0 2023 年 4 月 12 日
1.0.0 2022 年 1 月 22 日

#13#rsa-key

Download history 32/week @ 2024-03-13 24/week @ 2024-03-20 45/week @ 2024-03-27 68/week @ 2024-04-03 29/week @ 2024-04-10 26/week @ 2024-04-17 30/week @ 2024-04-24 23/week @ 2024-05-01 21/week @ 2024-05-08 26/week @ 2024-05-15 34/week @ 2024-05-22 30/week @ 2024-05-29 37/week @ 2024-06-05 53/week @ 2024-06-12 64/week @ 2024-06-19 30/week @ 2024-06-26

188 每月下载量
用于 sdjwt

MIT 许可证

71KB
1.5K SLoC

jsonwebtoken

这是 Keats 的 jsonwebtoken crate 的分支,使用 RustCrypto crates (rsa, sha2, hmac) 替代 Ring。这显著减少了 crate 中的工作量,并允许用户更灵活地加载 RSA 密钥。

注意事项

  • 不支持 ECDSA:我没有对 ECDSA 或使用 RustCrypto crates 研究和实现 EC 的时间需求,因此我移除了它以完全删除对 Ring 的依赖。
  • HMAC 签名验证不使用与 Keats 原始版本相同的时间常数比较。

有关 JSON Web Tokens 的更多信息,请参阅 JSON Web Tokens

安装

将以下内容添加到 Cargo.toml

jsonwebtoken-rustcrypto = "1"
serde = {version = "1", features = ["derive"] }

最低要求的 Rust 版本为 1.40。

算法

该库目前支持以下算法

  • HS256
  • HS384
  • HS512
  • RS256
  • RS384
  • RS512
  • PS256
  • PS384
  • PS512

已删除

  • ES256
  • ES384

如何使用

完整示例可在 examples 目录中找到:一个基本的示例和一个带有自定义头部的示例。

关于导入和结构体

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

/// Our claims struct, it needs to derive `Serialize` and/or `Deserialize`
#[derive(Debug, Serialize, Deserialize)]
struct Claims {
    sub: String,
    company: String,
    exp: usize,
}

Claims

可以验证的声明字段。(见 验证

#[derive(Debug, Serialize, Deserialize)]
struct Claims {
    aud: String,         // Optional. Audience
    exp: usize,          // Required (validate_exp defaults to true in validation). Expiration time (as UTC timestamp)
    iat: usize,          // Optional. Issued at (as UTC timestamp)
    iss: String,         // Optional. Issuer
    nbf: usize,          // Optional. Not Before (as UTC timestamp)
    sub: String,         // Optional. Subject (whom token refers to)
}

Header

默认算法是 HS256,它使用共享密钥。

let token = encode(&Header::default(), &my_claims, &EncodingKey::from_hmac_secret("secret".as_ref()))?;

自定义头部和更改算法

支持所有 RFC 参数,但默认头部仅设置了 typalg。如果您想设置 kid 参数或更改算法,例如

let mut header = Header::new(Algorithm::HS512);
header.kid = Some("blabla".to_owned());
let token = encode(&header, &my_claims, &EncodingKey::from_hmac_secret("secret".as_ref()))?;

请查看 examples/custom_header.rs 以获取完整的示例。

编码

// HS256
let token = encode(&Header::default(), &my_claims, &EncodingKey::from_hmac_secret("secret".as_ref()))?;
// RSA
let token = encode(&Header::new(Algorithm::RS256), &my_claims, &EncodingKey::from_rsa(RSAPrivateKey::new(&mut rng, bits).unwrap())?)?;

编码 JWT 需要 3 个参数

  • 一个头部:Header 结构体
  • 一些声明:您自己的结构体
  • 一个密钥/密钥

当使用HS256、HS2384或HS512时,密钥始终是像上面示例中那样的共享密钥。当使用RSA/EC时,密钥应该是PEM或DER格式中私钥的内容。

如果你的密钥是PEM格式,从性能角度考虑,最好在lazy_static或类似的结构中一次性生成EncodingKey并重复使用。

解码

// `token` is a struct with 2 fields: `header` and `claims` where `claims` is your own struct.
let token = decode::<Claims>(&token, &DecodingKey::from_hmac_secret("secret".as_ref()), &Validation::default())?;

decode可能会因为多种原因出错

  • 令牌或其签名无效
  • 令牌具有无效的base64
  • 至少有一个保留声明验证失败

与编码一样,当使用HS256、HS2384或HS512时,密钥始终是像上面示例中那样的共享密钥。当使用RSA/EC时,密钥应该是PEM或DER格式中公钥的内容。

在某些情况下,例如如果你不知道使用的算法或需要获取kid,你可以选择只解码头部

let header = decode_header(&token)?;

这不会执行任何签名验证或验证令牌声明。

你还可以使用RSA密钥的公钥组件以base64格式解码令牌。主要用例是JWK,其中你的公钥以如下JSON格式存在:查看rsa存储库的文档以获取说明。

{
   "kty":"RSA",
   "e":"AQAB",
   "kid":"6a7a119f-0876-4f7e-8d0f-bf3ea1391dd8",
   "n":"yRE6rHuNR0QbHO3H3Kt2pOKGVhQqGZXInOduQNxXzuKlvQTLUTv4l4sggh5_CYYi_cvI-SXVT9kPWSKXxJXBXd_4LkvcPuUakBoAkfh-eiFVMh2VrUyWyj3MFl0HTVF9KwRXLAcwkREiS3npThHRyIxuy0ZMeZfxVL5arMhw1SRELB8HoGfG_AtH89BIE9jDBHZ9dLelK9a184zAf8LwoPLxvJb3Il5nncqPcSfKDDodMFBIMc4lQzDKL5gvmiXLXB1AGLm8KBjfE8s3L5xqi-yUod-j8MtvIj812dkS4QMiRVN_by2h3ZY8LYVGrqZXZTcgn2ujn8uKjXLZVD5TdQ"
}

如果你的密钥是PEM格式,从性能角度考虑,最好在lazy_static或类似的结构中一次性生成DecodingKey并重复使用。

验证

use jsonwebtoken_rustcrypto::{Validation, Algorithm};

// Default validation: the only algo allowed is HS256
let validation = Validation::default();
// Quick way to setup a validation where only the algorithm changes
let validation = Validation::new(Algorithm::HS512);
// Adding some leeway (in seconds) for exp and nbf checks
let mut validation = Validation {leeway: 60, ..Default::default()};
// Checking issuer
let mut validation = Validation {iss: Some("issuer".to_string()), ..Default::default()};
// Setting audience
let mut validation = Validation::default();
validation.set_audience(&"Me"); // string
validation.set_audience(&["Me", "You"]); // array of strings

查看examples/validation.rs以获取完整的工作示例。

依赖项

~5MB
~109K SLoC