Фильтр эндпоинтов для 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);
let users_scope = utoipa_actix_web::scope("/users")
.wrap(JWTAuthorization)
.wrap(JWTAuthorization::default())
.service(routes::users::change_group)
.service(routes::users::change_username)
.service(routes::users::me);
let schedule_scope = utoipa_actix_web::scope("/schedule")
.wrap(JWTAuthorization)
.wrap(JWTAuthorization {
ignore: &["/group-names", "/teacher-names"],
})
.service(routes::schedule::schedule)
.service(routes::schedule::update_download_url)
.service(routes::schedule::cache_status)
@@ -51,7 +53,7 @@ pub fn get_api_scope<
.service(routes::schedule::teacher_names);
let fcm_scope = utoipa_actix_web::scope("/fcm")
.wrap(JWTAuthorization)
.wrap(JWTAuthorization::default())
.service(routes::fcm::update_callback)
.service(routes::fcm::set_token);

View File

@@ -8,7 +8,16 @@ use futures_util::future::LocalBoxFuture;
use std::future::{Ready, ready};
/// 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
where
@@ -23,12 +32,17 @@ where
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ready(Ok(JWTAuthorizationMiddleware { service }))
ready(Ok(JWTAuthorizationMiddleware {
service,
ignore: self.ignore,
}))
}
}
pub struct JWTAuthorizationMiddleware<S> {
service: S,
/// List of ignored endpoints.
ignore: &'static [&'static str],
}
impl<S, B> JWTAuthorizationMiddleware<S>
@@ -38,7 +52,7 @@ where
B: 'static,
{
/// Checking the validity of the token.
pub fn check_authorization(
fn check_authorization(
&self,
req: &HttpRequest,
payload: &mut Payload,
@@ -47,9 +61,25 @@ where
.map(|_| ())
.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;
}
impl<S, B> Service<ServiceRequest> for JWTAuthorizationMiddleware<S>
if let Some(other) = path.as_bytes().iter().nth(ignore.len()) {
return ['?' as u8, '/' as u8].contains(other);
}
true
})
}
}
impl<'a, S, B> Service<ServiceRequest> for JWTAuthorizationMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
@@ -62,6 +92,11 @@ where
forward_ready!(service);
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();
if let Err(err) = self.check_authorization(&http_req, &mut payload) {