Skip to content

Commit

Permalink
Starting token middleware impl
Browse files Browse the repository at this point in the history
  • Loading branch information
root authored and root committed Feb 5, 2024
1 parent 4cf7d01 commit 79621f7
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 2 deletions.
63 changes: 63 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ axum = "0.7"
tower-http = { version = "0.5.1", features = ["fs", "cors"] }
tower = { version = "0.4", features = ["full"] }
tower-cookies = "0.10"
lazy-regex = "3.1"
async-trait = "0.1"

[dev-dependencies]
anyhow = "1"
Expand Down
16 changes: 16 additions & 0 deletions src/ctx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#[derive(Clone, Debug)]
pub struct Ctx {
user_id: u64,
}

impl Ctx {
pub fn new(user_id: u64) -> Self {
Self { user_id }
}
}

impl Ctx {
pub fn user_id(&self) -> u64 {
self.user_id
}
}
5 changes: 5 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ pub type Result<T> = core::result::Result<T, Error>;
pub enum Error {
LoginFail,

// -- Auth Errors --
AuthFailNoAuthTokenCookie,
AuthFailTokenWrongFormat,
AuthFailCtxNotInRequestExt,

// -- Model Errors --
TicketDeleteFailIdNotFound { id: u64 },
}
Expand Down
8 changes: 6 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ use axum::{
};
use model::ModelController;
use tower_cookies::{CookieManager, CookieManagerLayer};
use web::mw_auth;

pub use self::error::{Error, Result};
use serde::Deserialize;
use tokio::net::TcpListener;
use tower_http::{
cors::{Any, CorsLayer},
services::ServeDir,
};

mod ctx;
mod error;
mod model;
mod web;
Expand All @@ -32,9 +33,12 @@ async fn main() -> Result<()> {
.allow_headers(vec![HeaderName::from_static("content-type")])
.allow_origin(Any);

let routes_apis = web::routes_tickets::routes(mc.clone())
.route_layer(middleware::from_fn(web::mw_auth::mw_require_auth));

let routes_all = Router::new()
.merge(web::routes_login::routes())
.nest("/api", web::routes_tickets::routes(mc.clone()))
.nest("/api", routes_apis)
.layer(cors)
.layer(middleware::map_response(main_response_mapper))
.layer(CookieManagerLayer::new())
Expand Down
1 change: 1 addition & 0 deletions src/web/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod mw_auth;
pub mod routes_login;
pub mod routes_tickets;

Expand Down
49 changes: 49 additions & 0 deletions src/web/mw_auth.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use crate::ctx::Ctx;
use crate::web::AUTH_TOKEN;
use crate::{Error, Result};
use async_trait::async_trait;
use axum::extract::FromRequestParts;
use axum::http::request::Parts;
use axum::RequestPartsExt;
use axum::{body::Body, extract::Request, middleware::Next, response::Response};
use lazy_regex::regex_captures;
use tower_cookies::Cookies;

pub async fn mw_require_auth(cookies: Cookies, req: Request<Body>, next: Next) -> Result<Response> {
let auth_token = cookies.get(AUTH_TOKEN).map(|c| c.to_string());

let (user_id, exp, sign) = auth_token
.ok_or(Error::AuthFailNoAuthTokenCookie)
.and_then(parse_token)?;

Ok(next.run(req).await)
}

#[async_trait]
impl<S: Send + Sync> FromRequestParts<S> for Ctx {
type Rejection = Error;

async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self> {
println!("->> {:<12} - Ctx", "EXTRACTOR");

parts
.extensions
.get::<Result<Ctx>>()
.ok_or(Error::AuthFailCtxNotInRequestExt)?
.clone()
}
}

// Parse token of format `user-[user-id]-[expiration].[signature]`
// Returns (user_id, expiration, signature)
fn parse_token(token: String) -> Result<(u64, String, String)> {
let (_whole, user_id, exp, sign) = regex_captures!(r#"^user-(\d+)\.(.+)\.(.+)"#, &token)
.ok_or(Error::AuthFailTokenWrongFormat)
.unwrap();

let user_id: u64 = user_id
.parse()
.map_err(|_| Error::AuthFailTokenWrongFormat)?;

Ok((user_id, exp.to_string(), sign.to_string()))
}

0 comments on commit 79621f7

Please sign in to comment.