JWT токены в Rust: библиотеки и реализация аутентификации
JSON Web Token (JWT) — это открытый стандарт для создания токенов доступа, основанный на формате JSON. В экосистеме Rust работа с JWT реализована через несколько качественных библиотек, среди которых лидирует jsonwebtoken. Этот инструмент обеспечивает полный цикл работы с токенами: создание, подписание, верификацию и декодирование.
Основные библиотеки для JWT в Rust
На текущий момент наиболее популярные крейты для работы с JWT:
- jsonwebtoken — основная библиотека с поддержкой HS256, RS256, EdDSA алгоритмов
- jwt — более легковесная альтернатива с базовым функционалом
- biscuit — продвинутая библиотека с поддержкой сложных сценариев
В этой статье мы сфокусируемся на jsonwebtoken как на самом зрелом и документированном решении.
Установка и настройка
Добавьте зависимость в Cargo.toml:
[dependencies]
jsonwebtoken = "9.3"
serde = { version = "1.0", features = ["derive"] }
chrono = "0.4"
Создание и верификация JWT токенов
Рассмотрим полный пример реализации аутентификации с JWT:
use jsonwebtoken::{encode, decode, Header, Validation, EncodingKey, DecodingKey};
use serde::{Serialize, Deserialize};
use chrono::{Utc, Duration};
#[derive(Debug, Serialize, Deserialize)]
struct Claims {
sub: String, // идентификатор пользователя
exp: usize, // время истечения токена
iat: usize, // время создания токена
role: String, // роль пользователя
}
fn create_token(user_id: &str, role: &str, secret: &str) -> Result {
let now = Utc::now();
let claims = Claims {
sub: user_id.to_string(),
exp: (now + Duration::hours(24)).timestamp() as usize,
iat: now.timestamp() as usize,
role: role.to_string(),
};
encode(
&Header::default(),
&claims,
&EncodingKey::from_secret(secret.as_bytes())
)
}
fn verify_token(token: &str, secret: &str) -> Result {
let token_data = decode::(
token,
&DecodingKey::from_secret(secret.as_bytes()),
&Validation::default()
)?;
Ok(token_data.claims)
}
Практическое использование в веб-приложении
Интеграция JWT с веб-фреймворками (например, Actix-web или Axum) требует создания middleware для проверки токенов:
use actix_web::{HttpRequest, HttpResponse, web, App, HttpServer, middleware::from_fn};
use std::sync::Arc;
// Middleware для проверки JWT
async fn auth_middleware(
req: HttpRequest,
) -> Result {
let auth_header = req.headers()
.get("Authorization")
.and_then(|v| v.to_str().ok())
.ok_or(HttpResponse::Unauthorized().json("Missing token"))?;
let token = auth_header
.strip_prefix("Bearer ")
.ok_or(HttpResponse::Unauthorized().json("Invalid token format"))?;
verify_token(token, SECRET)
.map_err(|_| HttpResponse::Unauthorized().json("Invalid token"))
}
// Защищенный эндпоинт
async fn protected_endpoint(claims: Claims) -> HttpResponse {
HttpResponse::Ok().json(claims)
}
Расширенные возможности и лучшие практики
- Refresh токены — используйте короткоживущие access токены (15-30 минут) и долгоживущие refresh токены (7-30 дней)
- Хранение секретов — никогда не храните секретные ключи в коде, используйте переменные окружения или безопасное хранилище
- Алгоритмы подписи — для продакшена используйте RS256 (асимметричное шифрование) вместо HS256
- Валидация claims — всегда проверяйте
exp,iss,audполя
Пример с асимметричным шифрованием (RS256)
use jsonwebtoken::{encode, decode, Header, Validation,
EncodingKey, DecodingKey, Algorithm};
fn create_rsa_token(user_id: &str, private_key_pem: &str) -> Result {
let claims = Claims { /* ... */ };
encode(
&Header::new(Algorithm::RS256),
&claims,
&EncodingKey::from_rsa_pem(private_key_pem.as_bytes())?
)
}
fn verify_rsa_token(token: &str, public_key_pem: &str) -> Result { Также в библиотеке
Очереди задач для Rust: обзор и примеры использования
Chalk для JavaScript (Node.js): полное руководство с примерами
JWT токены в JavaScript (Node.js): полное руководство
Тестирование в Java: фреймворки и инструменты (JUnit, TestNG, Mockito)