3 个稳定版本
1.2.0 | 2023 年 4 月 13 日 |
---|---|
1.1.0 | 2023 年 4 月 12 日 |
1.0.0 | 2022 年 1 月 22 日 |
#13 在 #rsa-key
188 每月下载量
用于 sdjwt
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 参数,但默认头部仅设置了 typ
和 alg
。如果您想设置 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