Skip to content

Commit

Permalink
modified the auth extractor
Browse files Browse the repository at this point in the history
  • Loading branch information
wpcodevo committed Aug 27, 2023
1 parent cf71f8a commit 09d86df
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 89 deletions.
76 changes: 47 additions & 29 deletions src/extractors/auth.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use actix_web::dev::{Service, ServiceRequest, ServiceResponse, Transform};
use actix_web::error::{ErrorForbidden, ErrorInternalServerError, ErrorUnauthorized};
use actix_web::{http, web, HttpMessage};
use actix_web::{http, web, FromRequest, HttpMessage};
use futures_util::future::{ready, LocalBoxFuture, Ready};
use futures_util::FutureExt;
use std::rc::Rc;
Expand All @@ -11,33 +11,48 @@ use crate::error::{ErrorMessage, ErrorResponse, HttpError};
use crate::models::{User, UserRole};
use crate::{utils, AppState};

pub struct RequireAuth;
pub struct Authenticated(User);

impl<S> Transform<S, ServiceRequest> for RequireAuth
where
S: Service<
ServiceRequest,
Response = ServiceResponse<actix_web::body::BoxBody>,
Error = actix_web::Error,
> + 'static,
{
type Response = ServiceResponse<actix_web::body::BoxBody>;
impl FromRequest for Authenticated {
type Error = actix_web::Error;
type Transform = AuthMiddleware<S>;
type InitError = ();
type Future = Ready<Result<Self::Transform, Self::InitError>>;
type Future = Ready<Result<Self, Self::Error>>;

fn from_request(
req: &actix_web::HttpRequest,
_payload: &mut actix_web::dev::Payload,
) -> Self::Future {
let value = req.extensions().get::<User>().cloned();
let result = match value {
Some(user) => Ok(Authenticated(user)),
None => Err(ErrorInternalServerError(HttpError::server_error(
"Authentication Error",
))),
};
ready(result)
}
}

fn new_transform(&self, service: S) -> Self::Future {
ready(Ok(AuthMiddleware {
service: Rc::new(service),
allowed_roles: vec![UserRole::User, UserRole::Moderator, UserRole::Admin],
}))
impl std::ops::Deref for Authenticated {
type Target = User;

fn deref(&self) -> &Self::Target {
&self.0
}
}

pub struct RequireOnlyAdmin;
pub struct RequireAuth {
pub allowed_roles: Rc<Vec<UserRole>>,
}

impl RequireAuth {
pub fn allowed_roles(allowed_roles: Vec<UserRole>) -> Self {
RequireAuth {
allowed_roles: Rc::new(allowed_roles),
}
}
}

impl<S> Transform<S, ServiceRequest> for RequireOnlyAdmin
impl<S> Transform<S, ServiceRequest> for RequireAuth
where
S: Service<
ServiceRequest,
Expand All @@ -54,14 +69,14 @@ where
fn new_transform(&self, service: S) -> Self::Future {
ready(Ok(AuthMiddleware {
service: Rc::new(service),
allowed_roles: vec![UserRole::Admin],
allowed_roles: self.allowed_roles.clone(),
}))
}
}

pub struct AuthMiddleware<S> {
service: Rc<S>,
allowed_roles: Vec<UserRole>,
allowed_roles: Rc<Vec<UserRole>>,
}

impl<S> Service<ServiceRequest> for AuthMiddleware<S>
Expand Down Expand Up @@ -153,18 +168,21 @@ mod tests {

use crate::{
db::DBClient,
extractors::auth::{RequireAuth, RequireOnlyAdmin},
extractors::auth::RequireAuth,
utils::{password, test_utils::get_test_config, token},
};

use super::*;

#[get("/", wrap = "RequireAuth")]
#[get(
"/",
wrap = "RequireAuth::allowed_roles(vec![UserRole::User, UserRole::Moderator, UserRole::Admin])"
)]
async fn handler_with_requireauth() -> HttpResponse {
HttpResponse::Ok().into()
}

#[get("/", wrap = "RequireOnlyAdmin")]
#[get("/", wrap = "RequireAuth::allowed_roles(vec![UserRole::Admin])")]
async fn handler_with_requireonlyadmin() -> HttpResponse {
HttpResponse::Ok().into()
}
Expand Down Expand Up @@ -215,9 +233,6 @@ mod tests {
.await
.unwrap();

let token =
token::create_token(&user.id.to_string(), config.jwt_secret.as_bytes(), 60).unwrap();

let app = test::init_service(
App::new()
.app_data(web::Data::new(AppState {
Expand All @@ -228,6 +243,9 @@ mod tests {
)
.await;

let token =
token::create_token(&user.id.to_string(), config.jwt_secret.as_bytes(), 60).unwrap();

let req = test::TestRequest::default()
.cookie(Cookie::new("token", token))
.to_request();
Expand Down
58 changes: 41 additions & 17 deletions src/scopes/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::{
},
error::{ErrorMessage, HttpError},
extractors::auth::RequireAuth,
models::UserRole,
utils::{password, token},
AppState,
};
Expand All @@ -20,7 +21,14 @@ pub fn auth_scope() -> Scope {
web::scope("/api/auth")
.route("/register", web::post().to(register))
.route("/login", web::post().to(login))
.route("/logout", web::post().to(logout).wrap(RequireAuth))
.route(
"/logout",
web::post().to(logout).wrap(RequireAuth::allowed_roles(vec![
UserRole::User,
UserRole::Moderator,
UserRole::Admin,
])),
)
}

#[utoipa::path(
Expand Down Expand Up @@ -527,10 +535,14 @@ mod tests {
env: config.clone(),
db_client,
}))
.service(
web::scope("/api/auth")
.route("/logout", web::post().to(logout).wrap(RequireAuth)),
),
.service(web::scope("/api/auth").route(
"/logout",
web::post().to(logout).wrap(RequireAuth::allowed_roles(vec![
UserRole::User,
UserRole::Moderator,
UserRole::Admin,
])),
)),
)
.await;

Expand Down Expand Up @@ -562,10 +574,14 @@ mod tests {
env: config.clone(),
db_client,
}))
.service(
web::scope("/api/auth")
.route("/logout", web::post().to(logout).wrap(RequireAuth)),
),
.service(web::scope("/api/auth").route(
"/logout",
web::post().to(logout).wrap(RequireAuth::allowed_roles(vec![
UserRole::User,
UserRole::Moderator,
UserRole::Admin,
])),
)),
)
.await;

Expand Down Expand Up @@ -608,10 +624,14 @@ mod tests {
env: config.clone(),
db_client,
}))
.service(
web::scope("/api/auth")
.route("/logout", web::post().to(logout).wrap(RequireAuth)),
),
.service(web::scope("/api/auth").route(
"/logout",
web::post().to(logout).wrap(RequireAuth::allowed_roles(vec![
UserRole::User,
UserRole::Moderator,
UserRole::Admin,
])),
)),
)
.await;

Expand Down Expand Up @@ -654,10 +674,14 @@ mod tests {
env: config.clone(),
db_client,
}))
.service(
web::scope("/api/auth")
.route("/logout", web::post().to(logout).wrap(RequireAuth)),
),
.service(web::scope("/api/auth").route(
"/logout",
web::post().to(logout).wrap(RequireAuth::allowed_roles(vec![
UserRole::User,
UserRole::Moderator,
UserRole::Admin,
])),
)),
)
.await;

Expand Down
Loading

0 comments on commit 09d86df

Please sign in to comment.