/
mxtn
/
webapi
Обзор
Документация
Войти
/
mxtn
/
webapi
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/middleware/jwt.rs
94 строки
4 KB
Max Talbushkin
First commit
10 июл 2025, 15:09
10 июл 2025, 15:09
cfeaa95
Код
Авторство
О чём код?
use actix_web::{dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform}, web, Error, HttpMessage}; use crate::errors::AppError; use crate::services::UserService; use crate::repositories::UserRepo; use futures::future::{ready, LocalBoxFuture, Ready}; use std::rc::Rc; // Middleware для проверки JWT-токена pub struct JwtMiddleware; // Реализация Transform для создания middleware impl<S, B> Transform<S, ServiceRequest> for JwtMiddleware where S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static, S::Future: 'static, B: 'static, { type Response = ServiceResponse<B>; type Error = Error; type InitError = (); type Transform = JwtMiddlewareService<S>; type Future = Ready<Result<Self::Transform, Self::InitError>>; fn new_transform(&self, service: S) -> Self::Future { ready(Ok(JwtMiddlewareService { service: Rc::new(service), })) } } // Сервис middleware pub struct JwtMiddlewareService<S> { service: Rc<S>, } impl<S, B> Service<ServiceRequest> for JwtMiddlewareService<S> where S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static, S::Future: 'static, B: 'static, { type Response = ServiceResponse<B>; type Error = Error; type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>; forward_ready!(service); #[allow(clippy::type_complexity)] fn call(&self, req: ServiceRequest) -> Self::Future { // Извлекаем пул и секрет из данных приложения let pool = match req.app_data::<web::Data<sqlx::PgPool>>() { Some(pool) => pool, None => return Box::pin(ready(Err(AppError::Internal.into()))), }; let jwt_secret = match req.app_data::<web::Data<String>>() { Some(secret) => secret, None => return Box::pin(ready(Err(AppError::Internal.into()))), }; // Проверяем, является ли запрос к /users или /login let path = req.path(); if path == "/users" && req.method() == actix_web::http::Method::POST { // Создание пользователя не требует JWT return Box::pin(self.service.call(req)); } if path == "/login" && req.method() == actix_web::http::Method::POST { // Логин не требует JWT return Box::pin(self.service.call(req)); } // Извлекаем токен из заголовка X-User-Access-Token let token = match req.headers().get("X-User-Access-Token") { Some(header) => match header.to_str() { Ok(token) => token, Err(_) => return Box::pin(ready(Err(AppError::AuthError.into()))), }, None => return Box::pin(ready(Err(AppError::AuthError.into()))), }; // Проверяем токен let repo = UserRepo::new(pool.as_ref().clone()); let service = UserService::new(repo, jwt_secret.as_ref().to_string()); let user_id = match service.validate_token(token) { Ok(id) => id, Err(_) => return Box::pin(ready(Err(AppError::AuthError.into()))), }; // Добавляем user_id в расширения запроса req.extensions_mut().insert(user_id); // Метод extensions_mut встроен в ServiceRequest // Передаем запрос дальше Box::pin(self.service.call(req)) } }