use std::cell::RefCell;
use std::pin::Pin;
use std::rc::Rc;
use std::sync::Arc;
use std::task::{Context, Poll};
use actix::dev::fut::Ready;
use actix_web::{Error, HttpResponse};
use actix_web::dev::{Service, ServiceRequest, ServiceResponse, Transform};
use futures::{Future, future};
use crate::api::models::UserIdentity;
use crate::domain::services::{UserSecurityService, UserService};
pub struct Auth {
pub user_security_service: Arc<dyn UserSecurityService>,
pub user_service: Arc<dyn UserService>,
}
impl Auth {
pub fn new(
user_security_service: Arc<dyn UserSecurityService>,
user_service: Arc<dyn UserService>,
) -> Self {
Auth { user_security_service, user_service }
}
}
impl<S: 'static, B> Transform<S> for Auth
where
S: Service<Request=ServiceRequest, Response=ServiceResponse<B>, Error=Error>,
S::Future: 'static,
B: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type Transform = AuthMiddleWare<S>;
type InitError = ();
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
future::ok(AuthMiddleWare {
service: Rc::new(RefCell::new(service)),
user_security_service: self.user_security_service.clone(),
user_service: self.user_service.clone(),
})
}
}
pub struct AuthMiddleWare<S> {
service: Rc<RefCell<S>>,
user_security_service: Arc<dyn UserSecurityService>,
user_service: Arc<dyn UserService>,
}
impl<S, B> Service for AuthMiddleWare<S>
where
S: Service<Request=ServiceRequest, Response=ServiceResponse<B>, Error=Error> + 'static,
S::Future: 'static,
B: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type Future = Pin<Box<dyn Future<Output=Result<Self::Response, Self::Error>>>>;
fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(ctx)
}
fn call(&mut self, req: Self::Request) -> Self::Future {
let user_security_service = self.user_security_service.clone();
let user_service = self.user_service.clone();
let mut service = self.service.clone();
Box::pin(async move {
let authorization = req
.headers()
.get("authorization")
.map(|v| v.to_str())
.unwrap_or(Ok(""))
.unwrap();
let parts: Vec<&str> = authorization.split(' ').collect();
if !(
parts.len() == 2 &&
!parts.is_empty() &&
parts[0].to_lowercase() == "bearer"
) {
return Ok(
req.into_response(
HttpResponse::Unauthorized()
.finish()
.into_body()
)
);
}
let token = parts[1];
if let Ok(token) = user_security_service.decode_token(token).await {
if let Ok(Some(user)) = user_service.find_by_email(&token.email).await {
let identity = UserIdentity {
email: user.email,
role: user.role,
user_id: user.id,
};
req.head()
.extensions_mut()
.insert(identity);
let res = service.call(req).await?;
return Ok(res);
}
}
Ok(
req.into_response(
HttpResponse::Unauthorized()
.finish()
.into_body()
)
)
})
}
}