Фильтр эндпоинтов для middleware.

This commit is contained in:
2025-04-16 16:20:32 +04:00
parent 5068fe3069
commit 9cc03c4ffe
2 changed files with 44 additions and 7 deletions

View File

@@ -35,13 +35,15 @@ pub fn get_api_scope<
.service(routes::auth::sign_up_vk); .service(routes::auth::sign_up_vk);
let users_scope = utoipa_actix_web::scope("/users") let users_scope = utoipa_actix_web::scope("/users")
.wrap(JWTAuthorization) .wrap(JWTAuthorization::default())
.service(routes::users::change_group) .service(routes::users::change_group)
.service(routes::users::change_username) .service(routes::users::change_username)
.service(routes::users::me); .service(routes::users::me);
let schedule_scope = utoipa_actix_web::scope("/schedule") let schedule_scope = utoipa_actix_web::scope("/schedule")
.wrap(JWTAuthorization) .wrap(JWTAuthorization {
ignore: &["/group-names", "/teacher-names"],
})
.service(routes::schedule::schedule) .service(routes::schedule::schedule)
.service(routes::schedule::update_download_url) .service(routes::schedule::update_download_url)
.service(routes::schedule::cache_status) .service(routes::schedule::cache_status)
@@ -51,7 +53,7 @@ pub fn get_api_scope<
.service(routes::schedule::teacher_names); .service(routes::schedule::teacher_names);
let fcm_scope = utoipa_actix_web::scope("/fcm") let fcm_scope = utoipa_actix_web::scope("/fcm")
.wrap(JWTAuthorization) .wrap(JWTAuthorization::default())
.service(routes::fcm::update_callback) .service(routes::fcm::update_callback)
.service(routes::fcm::set_token); .service(routes::fcm::set_token);

View File

@@ -8,7 +8,16 @@ use futures_util::future::LocalBoxFuture;
use std::future::{Ready, ready}; use std::future::{Ready, ready};
/// Middleware guard working with JWT tokens. /// Middleware guard working with JWT tokens.
pub struct JWTAuthorization; pub struct JWTAuthorization {
/// List of ignored endpoints.
pub ignore: &'static [&'static str],
}
impl Default for JWTAuthorization {
fn default() -> Self {
Self { ignore: &[] }
}
}
impl<S, B> Transform<S, ServiceRequest> for JWTAuthorization impl<S, B> Transform<S, ServiceRequest> for JWTAuthorization
where where
@@ -23,12 +32,17 @@ where
type Future = Ready<Result<Self::Transform, Self::InitError>>; type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future { fn new_transform(&self, service: S) -> Self::Future {
ready(Ok(JWTAuthorizationMiddleware { service })) ready(Ok(JWTAuthorizationMiddleware {
service,
ignore: self.ignore,
}))
} }
} }
pub struct JWTAuthorizationMiddleware<S> { pub struct JWTAuthorizationMiddleware<S> {
service: S, service: S,
/// List of ignored endpoints.
ignore: &'static [&'static str],
} }
impl<S, B> JWTAuthorizationMiddleware<S> impl<S, B> JWTAuthorizationMiddleware<S>
@@ -38,7 +52,7 @@ where
B: 'static, B: 'static,
{ {
/// Checking the validity of the token. /// Checking the validity of the token.
pub fn check_authorization( fn check_authorization(
&self, &self,
req: &HttpRequest, req: &HttpRequest,
payload: &mut Payload, payload: &mut Payload,
@@ -47,9 +61,25 @@ where
.map(|_| ()) .map(|_| ())
.map_err(|e| e.as_error::<authorized_user::Error>().unwrap().clone()) .map_err(|e| e.as_error::<authorized_user::Error>().unwrap().clone())
} }
fn should_skip(&self, req: &ServiceRequest) -> bool {
let path = req.match_info().unprocessed();
self.ignore.iter().any(|ignore| {
if !path.starts_with(ignore) {
return false;
}
if let Some(other) = path.as_bytes().iter().nth(ignore.len()) {
return ['?' as u8, '/' as u8].contains(other);
}
true
})
}
} }
impl<S, B> Service<ServiceRequest> for JWTAuthorizationMiddleware<S> impl<'a, S, B> Service<ServiceRequest> for JWTAuthorizationMiddleware<S>
where where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>, S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static, S::Future: 'static,
@@ -62,6 +92,11 @@ where
forward_ready!(service); forward_ready!(service);
fn call(&self, req: ServiceRequest) -> Self::Future { fn call(&self, req: ServiceRequest) -> Self::Future {
if self.should_skip(&req) {
let fut = self.service.call(req);
return Box::pin(async move { Ok(fut.await?.map_into_left_body()) });
}
let (http_req, mut payload) = req.into_parts(); let (http_req, mut payload) = req.into_parts();
if let Err(err) = self.check_authorization(&http_req, &mut payload) { if let Err(err) = self.check_authorization(&http_req, &mut payload) {