Авторизация и аутентификация в Rust: полное руководство

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Авторизация и аутентификация в Rust: полное руководство для разработчиков

Rust — язык системного программирования, который набирает популярность для создания высоконагруженных и безопасных веб-сервисов. Однако реализация аутентификации (проверки личности) и авторизации (проверки прав доступа) в Rust требует особого подхода из-за строгой системы типов и отсутствия встроенных решений. В этой статье мы разберём ключевые библиотеки и практические примеры.

Почему Rust для аутентификации?

Безопасность — главный приоритет Rust. Компилятор предотвращает утечки памяти, гонки данных и многие уязвимости, характерные для C/C++. Однако реализация аутентификации вручную может привести к ошибкам, поэтому сообщество создало несколько зрелых библиотек.

Основные библиотеки для аутентификации в Rust

1. actix-web-httpauth — для веб-фреймворка Actix-web

Самая популярная библиотека для реализации HTTP-аутентификации (Basic, Bearer, Digest) в экосистеме Actix-web.

2. jsonwebtoken — работа с JWT

Полноценная реализация JSON Web Tokens (JWT) для Rust. Поддерживает RS256, HS256, ES256 и другие алгоритмы.

3. bcrypt — хеширование паролей

Надёжная библиотека для хеширования паролей алгоритмом bcrypt с автоматической генерацией соли.

4. argon2 — современное хеширование

Если bcrypt кажется устаревшим, используйте Argon2 — победитель конкурса Password Hashing Competition.

5. tower-http — middleware для авторизации

Позволяет создавать переиспользуемые middleware для проверки прав доступа в любом HTTP-сервере на основе Tower.

Практический пример: аутентификация через JWT в Actix-web

Рассмотрим минимальный пример сервера с регистрацией и логином. Сначала добавьте зависимости в Cargo.toml:

[dependencies]
actix-web = "4"
actix-web-httpauth = "0.8"
jsonwebtoken = "9"
bcrypt = "0.15"
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["full"] }

Теперь напишем структуру пользователя и функции для создания/проверки JWT:

use actix_web::{web, App, HttpServer, HttpResponse, HttpRequest};
use actix_web_httpauth::extractors::bearer::BearerAuth;
use jsonwebtoken::{encode, decode, Header, Validation, EncodingKey, DecodingKey};
use bcrypt::{hash, verify, DEFAULT_COST};
use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize)]
struct Claims {
    sub: String, // email пользователя
    exp: usize,  // время истечения токена
}

#[derive(Debug, Serialize, Deserialize)]
struct User {
    email: String,
    password_hash: String,
}

// Хранилище пользователей (в реальности — БД)
static USERS: once_cell::sync::Lazy<std::sync::Mutex<Vec<User>>> =
    once_cell::sync::Lazy::new(|| std::sync::Mutex::new(vec![]));

async fn register(info: web::Json<UserInput>) -> HttpResponse {
    let hashed = hash(&info.password, DEFAULT_COST).unwrap();
    let user = User {
        email: info.email.clone(),
        password_hash: hashed,
    };
    USERS.lock().unwrap().push(user);
    HttpResponse::Ok().json("User registered")
}

async fn login(info: web::Json<UserInput>) -> HttpResponse {
    let users = USERS.lock().unwrap();
    if let Some(user) = users.iter().find(|u| u.email == info.email) {
        if verify(&info.password, &user.password_hash).unwrap() {
            let claims = Claims {
                sub: info.email.clone(),
                exp: 10000000000,
            };
            let token = encode(
                &Header::default(),
                &claims,
                &EncodingKey::from_secret(b"secret_key"),
            ).unwrap();
            return HttpResponse::Ok().json(token);
        }
    }
    HttpResponse::Unauthorized().json("Invalid credentials")
}

async fn protected(auth: BearerAuth) -> HttpResponse {
    let token = auth.token();
    let token_data = decode::<Claims>(
        token,
        &DecodingKey::from_secret(b"secret_key"),
        &Validation::default(),
    );
    match token_data {
        Ok(data) => HttpResponse::Ok().json(format!("Hello, {}!", data.claims.sub)),
        Err(_) => HttpResponse::Unauthorized().json("Invalid token"),
    }
}

Авторизация на основе ролей (RBAC)

Простая авторизация может быть реализована через расширение Claims в JWT:

#[derive(Debug, Serialize, Deserialize)]
struct Claims {
    sub: String,
    role: String, // "admin", "user", "moderator"
    exp: usize,
}

// Middleware проверки роли
fn require_role(role: &                    

Рекомендаций