51个版本 (稳定)
9.3.0 | 2024年3月21日 |
---|---|
9.2.0 | 2023年12月1日 |
9.1.0 | 2023年10月21日 |
8.3.0 | 2023年3月15日 |
0.2.0 | 2015年11月8日 |
#4 in Web编程
1,702,555 每月下载量
用于 995 个crate (429个直接使用)
105KB
2K SLoC
jsonwebtoken
有关JSON Web Tokens的更多信息,请参阅 JSON Web Tokens。
安装
将以下内容添加到Cargo.toml中
jsonwebtoken = "9"
# If you do not need pem decoding, you can disable the default feature `use_pem` that way:
# jsonwebtoken = {version = "9", default-features = false }
serde = {version = "1.0", features = ["derive"] }
最低要求的Rust版本(MSRV)是1.67。
算法
此库目前支持以下算法
- HS256
- HS384
- HS512
- RS256
- RS384
- RS512
- PS256
- PS384
- PS512
- ES256
- ES384
- EdDSA
如何使用
完整示例位于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,
}
声明
可以验证的声明字段。(见验证)
#[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)
}
头部
默认算法是HS256,它使用共享密钥。
let token = encode(&Header::default(), &my_claims, &EncodingKey::from_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_secret("secret".as_ref()))?;
请参阅 examples/custom_header.rs
以获取完整的示例。
编码
// HS256
let token = encode(&Header::default(), &my_claims, &EncodingKey::from_secret("secret".as_ref()))?;
// RSA
let token = encode(&Header::new(Algorithm::RS256), &my_claims, &EncodingKey::from_rsa_pem(include_bytes!("privkey.pem"))?)?;
编码JWT需要三个参数
- 一个头部:
Header
结构体 - 一些声明:您自己的结构体
- 一个密钥/密钥
当使用HS256、HS384或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_secret("secret".as_ref()), &Validation::default())?;
decode
可能由于多种原因导致错误
- 令牌或其签名无效
- 令牌包含无效的 base64 编码
- 至少一个保留声明的验证失败
与编码一样,当使用 HS256、HS384 或 HS512 时,密钥始终是一个共享密钥,例如上面示例中的情况。当使用 RSA/EC 时,密钥应该是 PEM(或在这种情况下是证书)格式中的公钥内容或 DER 格式。
在某些情况下,例如如果您不知道使用的算法或需要抓取 kid
,您可以选择仅解码头部
let header = decode_header(&token)?;
这不会执行任何签名验证或验证令牌声明。
您还可以使用 RSA 密钥的公钥组件(以 base64 格式)来解码令牌。主要用例是 JWK,其中您的公钥以如下 JSON 格式存在
{
"kty":"RSA",
"e":"AQAB",
"kid":"6a7a119f-0876-4f7e-8d0f-bf3ea1391dd8",
"n":"yRE6rHuNR0QbHO3H3Kt2pOKGVhQqGZXInOduQNxXzuKlvQTLUTv4l4sggh5_CYYi_cvI-SXVT9kPWSKXxJXBXd_4LkvcPuUakBoAkfh-eiFVMh2VrUyWyj3MFl0HTVF9KwRXLAcwkREiS3npThHRyIxuy0ZMeZfxVL5arMhw1SRELB8HoGfG_AtH89BIE9jDBHZ9dLelK9a184zAf8LwoPLxvJb3Il5nncqPcSfKDDodMFBIMc4lQzDKL5gvmiXLXB1AGLm8KBjfE8s3L5xqi-yUod-j8MtvIj812dkS4QMiRVN_by2h3ZY8LYVGrqZXZTcgn2ujn8uKjXLZVD5TdQ"
}
// `token` is a struct with 2 fields: `header` and `claims` where `claims` is your own struct.
let token = decode::<Claims>(&token, &DecodingKey::from_rsa_components(jwk["n"], jwk["e"]), &Validation::new(Algorithm::RS256))?;
如果您的密钥是 PEM 格式,从性能角度考虑,最好在 lazy_static
或类似结构中一次性生成 DecodingKey
并重复使用。
将 SEC1 私钥转换为 PKCS8
jsonwebtoken
当前仅支持私 EC 密钥的 PKCS8 格式。如果您的密钥顶部有 BEGIN EC PRIVATE KEY
,这是一个 SEC1 类型,可以转换为 PKCS8,如下所示
openssl pkcs8 -topk8 -nocrypt -in sec1.pem -out pkcs8.pem
验证
此库会自动验证 exp
声明,如果存在,还会验证 nbf
。您还可以验证 sub
、iss
和 aud
,但这些需要在 Validation
结构中设置预期值。在 aud
的情况下,如果令牌中有值但 Validation
中没有设置,则令牌将被拒绝。
由于时钟偏移,验证时间字段始终有点棘手,您可以通过设置 leeway
字段来为 iat
、exp
和 nbf
验证添加一些宽容度。
最后但同样重要的是,如果您不使用 HS256
,则需要设置此令牌允许的算法。
查看 examples/validation.rs
以获取完整的示例。
依赖项
~1–11MB
~129K SLoC