JWT токены в Rust: библиотека jsonwebtoken
JSON Web Tokens (JWT) — это открытый стандарт (RFC 7519) для создания токенов доступа, основанных на JSON. В экосистеме Rust одной из самых популярных и стабильных библиотек для работы с JWT является jsonwebtoken. Она предоставляет полный набор функций для создания, подписи, верификации и декодирования JWT токенов, поддерживая как симметричные (HS256, HS384, HS512), так и асимметричные (RS256, RS384, RS512, ES256, ES384) алгоритмы шифрования.
Установка и настройка
Для начала работы добавьте зависимость в файл Cargo.toml вашего проекта:
[dependencies]
jsonwebtoken = "9.3"
serde = { version = "1.0", features = ["derive"] }
chrono = "0.4"
Библиотека serde необходима для сериализации и десериализации данных токена, а chrono упрощает работу с временными метками (exp, iat, nbf).
Базовая структура JWT
JWT токен состоит из трех частей: заголовок (header), полезная нагрузка (claims) и подпись. В Rust это реализуется через структуры:
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
struct Claims {
sub: String, // субъект (обычно ID пользователя)
exp: usize, // время истечения (unix timestamp)
iat: usize, // время создания (unix timestamp)
role: String, // кастомное поле
}
Создание и подпись JWT токена
Рассмотрим полный пример создания токена с использованием алгоритма HS256 (симметричное шифрование):
use jsonwebtoken::{encode, Header, EncodingKey};
use chrono::Utc;
fn create_jwt(user_id: &str, secret: &str) -> Result {
let now = Utc::now().timestamp() as usize;
let claims = Claims {
sub: user_id.to_string(),
exp: now + 3600, // токен действителен 1 час
iat: now,
role: "user".to_string(),
};
let token = encode(
&Header::default(), // по умолчанию HS256
&claims,
&EncodingKey::from_secret(secret.as_bytes()),
)?;
Ok(token)
}
Верификация и декодирование токена
Для проверки подлинности токена используется функция decode с указанием алгоритма и секретного ключа:
use jsonwebtoken::{decode, DecodingKey, Validation, Algorithm};
fn verify_jwt(token: &str, secret: &str) -> Result {
let validation = Validation::new(Algorithm::HS256);
let token_data = decode::(
token,
&DecodingKey::from_secret(secret.as_bytes()),
&validation,
)?;
Ok(token_data.claims)
}
Работа с асимметричными алгоритмами (RS256)
Для production-среды рекомендуется использовать асимметричное шифрование. Пример с RS256:
use jsonwebtoken::{encode, decode, Header, EncodingKey, DecodingKey, Validation, Algorithm};
// Создание токена с приватным ключом
fn create_rs256_token(user_id: &str, private_key_pem: &str) -> Result> {
let claims = Claims {
sub: user_id.to_string(),
exp: (Utc::now().timestamp() + 3600) as usize,
iat: Utc::now().timestamp() as usize,
role: "admin".to_string(),
};
let token = encode(
&Header::new(Algorithm::RS256),
&claims,
&EncodingKey::from_rsa_pem(private_key_pem.as_bytes())?,
)?;
Ok(token)
}
// Верификация с публичным ключом
fn verify_rs256_token(token: &str, public_key_pem: &str) -> Result> {
let mut validation = Validation::new(Algorithm::RS256);
validation.validate_exp = true; // проверка срока действия
let token_data = decode::(
token,
&DecodingKey::from_rsa_pem(public_key_pem.as_bytes())?,
&validation,
)?;
Ok(token_data.claims)
}
Расширенные возможности и валидация
Библиотека предоставляет тонкую настройку валидации через структуру Validation:
use jsonwebtoken::Validation;
// Кастомная валидация
fn custom_validation() -> Validation {
let mut validation = Validation::new(Algorithm::HS256);
validation.leeway = 60; // допустимое отклонение во времени (сек)
validation.validate_exp = true; // проверять exp
validation.validate_iat = true; // проверять iat
validation.required_specific_claims