diff --git a/Cargo.lock b/Cargo.lock index ae97711..754805a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -594,6 +594,7 @@ name = "learn_axum" version = "0.1.0" dependencies = [ "anyhow", + "async-trait", "axum", "httpc-test", "lazy-regex", diff --git a/Cargo.toml b/Cargo.toml index d30d781..d32e180 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ tower-http = { version = "0.4.4", features = ["fs"] } tower-cookies = "0.9" # Others lazy-regex = "3" +async-trait = "0.1" [dev-dependencies] anyhow = "1" diff --git a/src/ctx.rs b/src/ctx.rs new file mode 100644 index 0000000..4cd72ef --- /dev/null +++ b/src/ctx.rs @@ -0,0 +1,18 @@ +#[derive(Debug, Clone)] +pub struct Ctx { + user_id: u64, +} + +// Constructor +impl Ctx { + pub fn new(user_id: u64) -> Self { + Self { user_id } + } +} + +// Property Accessors. +impl Ctx { + pub fn user_id(&self) -> u64 { + self.user_id + } +} diff --git a/src/main.rs b/src/main.rs index 14f0557..faba86f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,7 +16,7 @@ use serde::Deserialize; use tower_http::services::ServeDir; use tower_cookies::CookieManagerLayer; - +mod ctx; mod error; mod web; mod model; diff --git a/src/web/mw_auth.rs b/src/web/mw_auth.rs index 9aca7fc..2210bf9 100644 --- a/src/web/mw_auth.rs +++ b/src/web/mw_auth.rs @@ -1,9 +1,14 @@ +use async_trait::async_trait; +use axum::RequestPartsExt; +use axum::extract::FromRequestParts; use axum::http::Request; +use axum::http::request::Parts; use axum::middleware::Next; use axum::response::Response; use lazy_regex::regex_captures; use tower_cookies::Cookies; +use crate::ctx::Ctx; use crate::web::AUTH_TOKEN; use crate::{Error, Result}; @@ -25,6 +30,34 @@ pub async fn mw_require_auth( Ok(next.run(req).await) } +// region: --- Ctx Extractor + +// TODO: Find out what all this syntax means +#[async_trait] +impl FromRequestParts for Ctx { + type Rejection = Error; + + async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result { + println!("->> {:<12} - Ctx", "EXTRACTOR"); + + // Use the cookies extractor. + let cookies = parts.extract::().await.unwrap(); + + let auth_token = cookies.get(AUTH_TOKEN).map(|c| c.value().to_string()); + + // Parse token. + let (user_id, exp, sign) = auth_token + .ok_or(Error::AuthFailNoAuthTokenCookie) + .and_then(parse_token)?; + + // TODO: Token components validation. + + Ok(Ctx::new(user_id)) + } +} + +// endregion: --- Ctx Extractor + /// Parse a token of format `user-[user-id].[expiration].[signature]` /// Returns (user-id, expiration, signature) fn parse_token(token: String) -> Result<(u64, String, String)> {