This commit is contained in:
Imbus 2023-11-17 07:04:43 +01:00
commit a8b62a4e89
6 changed files with 1651 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

1512
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

12
Cargo.toml Normal file
View file

@ -0,0 +1,12 @@
[package]
name = "actix-middleware-demo"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
actix-web = { version = "4.4.0", features = ["rustls"] }
futures-util = "0.3.29"
serde = { version = "1.0.190", features = ["derive"] }
serde_json = "1.0.107"

1
postdata.nu Normal file
View file

@ -0,0 +1 @@
http post -t application/json http://localhost:8080 { demo: "Whatever 123" }

89
src/auth_middleware.rs Normal file
View file

@ -0,0 +1,89 @@
use std::future::{ready, Ready};
use actix_web::{
dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
Error, HttpMessage,
};
use futures_util::{future::LocalBoxFuture, FutureExt};
use std::rc::Rc;
// This is where you would store your authentication data
pub struct AuthData;
pub struct AuthenticationResult;
impl AuthData {
pub async fn authenticate(
&self,
_id: Option<String>,
) -> Result<Option<AuthenticationResult>, Error> {
Ok(Some(AuthenticationResult))
}
}
pub type AuthenticationInfo = Rc<AuthenticationResult>;
pub struct AuthenticationMiddleware<S> {
auth_data: Rc<AuthData>,
service: Rc<S>,
}
impl<S, B> Service<ServiceRequest> for AuthenticationMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
forward_ready!(service);
fn call(&self, req: ServiceRequest) -> Self::Future {
let srv = self.service.clone();
let auth_data = self.auth_data.clone();
async move {
let id = req
.headers()
.get("X-Auth-Id")
.map(|id| id.to_str().unwrap().to_owned());
let auth = auth_data.authenticate(id).await?;
if let Some(auth) = auth {
req.extensions_mut()
.insert::<AuthenticationInfo>(Rc::new(auth));
}
let res = srv.call(req).await?;
Ok(res)
}
.boxed_local()
}
}
pub struct AuthenticateMiddlewareFactory {
auth_data: Rc<AuthData>,
}
impl AuthenticateMiddlewareFactory {
pub fn new(auth_data: AuthData) -> Self {
AuthenticateMiddlewareFactory {
auth_data: Rc::new(auth_data),
}
}
}
impl<S, B> Transform<S, ServiceRequest> for AuthenticateMiddlewareFactory
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type Transform = AuthenticationMiddleware<S>;
type InitError = ();
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ready(Ok(AuthenticationMiddleware {
auth_data: self.auth_data.clone(),
service: Rc::new(service),
}))
}
}

36
src/main.rs Normal file
View file

@ -0,0 +1,36 @@
use actix_web::{get, post, web::Json, App, HttpResponse, HttpServer, Responder};
use serde::Deserialize;
mod auth_middleware;
#[derive(Deserialize)]
struct Data {
demo: String,
}
#[get("/")]
async fn index() -> impl Responder {
HttpResponse::Ok().body("Actix is alive!")
}
#[post("/")]
async fn postfunction(json: Json<Data>) -> impl Responder {
HttpResponse::Ok().body(json.demo.clone())
}
#[actix_web::main] // Same as #[tokio::main]
async fn main() -> std::io::Result<()> {
println!("Serving at http://localhost:8080");
HttpServer::new(|| {
App::new()
.wrap(auth_middleware::AuthenticateMiddlewareFactory::new(
auth_middleware::AuthData,
))
.service(index)
.service(postfunction)
})
.bind("0.0.0.0:8080")
.unwrap()
.run()
.await
}