From 1add903f363f5f9a490c756ed3acf06bee49aab6 Mon Sep 17 00:00:00 2001 From: N08I40K Date: Thu, 27 Mar 2025 20:03:35 +0400 Subject: [PATCH] 0.6.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Добавлена проверка токена пользователя для перед обработкой запроса. --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/extractors/authorized_user.rs | 14 ++---- src/main.rs | 11 +++-- src/middlewares/authorization.rs | 79 +++++++++++++++++++++++++++++++ src/middlewares/mod.rs | 1 + 6 files changed, 94 insertions(+), 15 deletions(-) create mode 100644 src/middlewares/authorization.rs create mode 100644 src/middlewares/mod.rs diff --git a/Cargo.lock b/Cargo.lock index e5cf2fc..3521f61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2351,7 +2351,7 @@ dependencies = [ [[package]] name = "schedule-parser-rusted" -version = "0.5.0" +version = "0.6.0" dependencies = [ "actix-macros 0.1.0", "actix-test", diff --git a/Cargo.toml b/Cargo.toml index edcd146..ac8c6d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = ["actix-macros", "actix-test"] [package] name = "schedule-parser-rusted" -version = "0.5.0" +version = "0.6.0" edition = "2024" publish = false diff --git a/src/extractors/authorized_user.rs b/src/extractors/authorized_user.rs index baa0cb2..3e4733a 100644 --- a/src/extractors/authorized_user.rs +++ b/src/extractors/authorized_user.rs @@ -10,20 +10,18 @@ use actix_web::{HttpRequest, web}; use derive_more::Display; use serde::{Deserialize, Serialize}; use std::fmt::Debug; +use actix_web::http::header; #[derive(Clone, Debug, Serialize, Deserialize, Display, ResponseErrorMessage)] #[status_code = "actix_web::http::StatusCode::UNAUTHORIZED"] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum Error { - #[display("No authorization header found")] + #[display("No Authorization header found")] NoHeader, #[display("Bearer token is required")] UnknownAuthorizationType, - #[display("No bearer token provided")] - NoBearerToken, - #[display("Invalid or expired access token")] InvalidAccessToken, @@ -43,7 +41,7 @@ impl FromRequestSync for User { fn from_request_sync(req: &HttpRequest, _: &mut Payload) -> Result { let authorization = req .headers() - .get("Authorization") + .get(header::AUTHORIZATION) .ok_or(Error::NoHeader.into_err())? .to_str() .map_err(|_| Error::NoHeader.into_err())? @@ -51,14 +49,10 @@ impl FromRequestSync for User { let parts: Vec<&str> = authorization.split(' ').collect(); - if parts.len() == 0 || parts[0] != "Bearer" { + if parts.len() != 2 || parts[0] != "Bearer" { return Err(Error::UnknownAuthorizationType.into_err()); } - if parts.len() < 2 { - return Err(Error::NoBearerToken.into()); - } - let user_id = jwt::verify_and_decode(&parts[1].to_string()) .map_err(|_| Error::InvalidAccessToken.into_err())?; diff --git a/src/main.rs b/src/main.rs index c708e0d..a5796bb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,9 @@ -use crate::app_state::{AppState, app_state}; +use crate::app_state::{app_state, AppState}; +use crate::middlewares::authorization::Authorization; use crate::routes::auth::sign_in::{sign_in_default, sign_in_vk}; use crate::routes::auth::sign_up::{sign_up_default, sign_up_vk}; use crate::routes::users::me::me; -use actix_web::{App, HttpServer, web}; +use actix_web::{web, App, HttpServer}; use dotenvy::dotenv; mod app_state; @@ -13,6 +14,7 @@ mod parser; mod xls_downloader; mod extractors; +mod middlewares; mod routes; mod utility; @@ -32,7 +34,10 @@ async fn main() { .service(sign_in_vk) .service(sign_up_default) .service(sign_up_vk); - let users_scope = web::scope("/users").service(me); + + let users_scope = web::scope("/users") + .wrap(Authorization) + .service(me); let api_scope = web::scope("/api/v1") .service(auth_scope) diff --git a/src/middlewares/authorization.rs b/src/middlewares/authorization.rs new file mode 100644 index 0000000..ca85abe --- /dev/null +++ b/src/middlewares/authorization.rs @@ -0,0 +1,79 @@ +use crate::database::models::User; +use crate::extractors::authorized_user; +use crate::extractors::base::FromRequestSync; +use actix_web::body::{BoxBody, EitherBody}; +use actix_web::dev::{Payload, Service, ServiceRequest, ServiceResponse, Transform, forward_ready}; +use actix_web::{Error, HttpRequest, ResponseError}; +use futures_util::future::LocalBoxFuture; +use std::future::{Ready, ready}; + +pub struct Authorization; + +impl Transform for Authorization +where + S: Service, Error = Error>, + S::Future: 'static, + B: 'static, +{ + type Response = ServiceResponse>; + type Error = Error; + type Transform = AuthorizationMiddleware; + type InitError = (); + type Future = Ready>; + + fn new_transform(&self, service: S) -> Self::Future { + ready(Ok(AuthorizationMiddleware { service })) + } +} + +pub struct AuthorizationMiddleware { + service: S, +} + +impl AuthorizationMiddleware +where + S: Service, Error = Error>, + S::Future: 'static, + B: 'static, +{ + pub fn check_authorization( + &self, + req: &HttpRequest, + payload: &mut Payload, + ) -> Result<(), authorized_user::Error> { + User::from_request_sync(req, payload) + .map(|_| ()) + .map_err(|e| e.as_error::().unwrap().clone()) + } +} + +impl Service for AuthorizationMiddleware +where + S: Service, Error = Error>, + S::Future: 'static, + B: 'static, +{ + type Response = ServiceResponse>; + type Error = Error; + type Future = LocalBoxFuture<'static, Result>; + + forward_ready!(service); + + fn call(&self, req: ServiceRequest) -> Self::Future { + let (http_req, mut payload) = req.into_parts(); + + if let Err(err) = self.check_authorization(&http_req, &mut payload) { + return Box::pin(async move { + Ok(ServiceResponse::new( + http_req, + err.error_response().map_into_right_body(), + )) + }); + } + + let req = ServiceRequest::from_parts(http_req, payload); + let fut = self.service.call(req); + + Box::pin(async move { Ok(fut.await?.map_into_left_body()) }) + } +} diff --git a/src/middlewares/mod.rs b/src/middlewares/mod.rs new file mode 100644 index 0000000..3e8f8bd --- /dev/null +++ b/src/middlewares/mod.rs @@ -0,0 +1 @@ +pub mod authorization; \ No newline at end of file