feat: add auth things

This commit is contained in:
Sandro Eiler 2023-10-07 22:14:22 +02:00
parent 42a75ba800
commit 88c4045d33
7 changed files with 182 additions and 20 deletions

97
Cargo.lock generated
View file

@ -17,6 +17,15 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aho-corasick"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.71" version = "1.0.71"
@ -42,9 +51,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]] [[package]]
name = "axum" name = "axum"
version = "0.6.18" version = "0.6.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"axum-core", "axum-core",
@ -412,9 +421,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
[[package]] [[package]]
name = "httpc-test" name = "httpc-test"
version = "0.1.4" version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e7d56c0f391b27f6b4186e9ad7dad17c2f80329a8a409312a6e7622a25379f3" checksum = "81a425cb8352fb5080b3622e8a4265c63e75bedd68a4c19a83f7d4c88f9c9667"
dependencies = [ dependencies = [
"cookie 0.16.2", "cookie 0.16.2",
"http", "http",
@ -449,7 +458,7 @@ dependencies = [
"httpdate", "httpdate",
"itoa", "itoa",
"pin-project-lite", "pin-project-lite",
"socket2", "socket2 0.4.9",
"tokio", "tokio",
"tower-service", "tower-service",
"tracing", "tracing",
@ -551,6 +560,29 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "lazy-regex"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e723bd417b2df60a0f6a2b6825f297ea04b245d4ba52b5a22cb679bdf58b05fa"
dependencies = [
"lazy-regex-proc_macros",
"once_cell",
"regex",
]
[[package]]
name = "lazy-regex-proc_macros"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f0a1d9139f0ee2e862e08a9c5d0ba0470f2aa21cd1e1aa1b1562f83116c725f"
dependencies = [
"proc-macro2",
"quote",
"regex",
"syn",
]
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.4.0"
@ -564,6 +596,7 @@ dependencies = [
"anyhow", "anyhow",
"axum", "axum",
"httpc-test", "httpc-test",
"lazy-regex",
"serde", "serde",
"serde_json", "serde_json",
"tokio", "tokio",
@ -791,9 +824,9 @@ dependencies = [
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.9" version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
[[package]] [[package]]
name = "pin-utils" name = "pin-utils"
@ -850,6 +883,35 @@ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
] ]
[[package]]
name = "regex"
version = "1.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
[[package]] [[package]]
name = "reqwest" name = "reqwest"
version = "0.11.18" version = "0.11.18"
@ -1058,6 +1120,16 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "socket2"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e"
dependencies = [
"libc",
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.22" version = "2.0.22"
@ -1153,11 +1225,10 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.29.1" version = "1.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9"
dependencies = [ dependencies = [
"autocfg",
"backtrace", "backtrace",
"bytes", "bytes",
"libc", "libc",
@ -1166,7 +1237,7 @@ dependencies = [
"parking_lot", "parking_lot",
"pin-project-lite", "pin-project-lite",
"signal-hook-registry", "signal-hook-registry",
"socket2", "socket2 0.5.4",
"tokio-macros", "tokio-macros",
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
@ -1241,9 +1312,9 @@ dependencies = [
[[package]] [[package]]
name = "tower-http" name = "tower-http"
version = "0.4.1" version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8bd22a874a2d0b70452d5597b12c537331d49060824a95f49f108994f94aa4c" checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140"
dependencies = [ dependencies = [
"bitflags 2.3.3", "bitflags 2.3.3",
"bytes", "bytes",

View file

@ -6,13 +6,17 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
tokio = { version = "1.29.1", features = ["full"] } tokio = { version = "1.32.0", features = ["full"] }
axum = "0.6.18" # Serde / json
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1" serde_json = "1"
tower-http = { version = "0.4.1", features = ["fs"] } # Axum
axum = { version = "0.6.20" }
tower-http = { version = "0.4.4", features = ["fs"] }
tower-cookies = "0.9" tower-cookies = "0.9"
# Others
lazy-regex = "3"
[dev-dependencies] [dev-dependencies]
anyhow = "1" anyhow = "1"
httpc-test = "0.1.1" httpc-test = "0.1.5"

View file

@ -6,6 +6,12 @@ pub type Result<T> = core::result::Result<T, Error>;
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
LoginFail, LoginFail,
// -- Auth errors.
AuthFailNoAuthTokenCookie,
AuthFailTokenWrongFormat,
// -- Model errors.
PropertyDeleteFailIdNotFound { id: u64 }, PropertyDeleteFailIdNotFound { id: u64 },
} }

View file

@ -1,5 +1,7 @@
#![allow(unused)] #![allow(unused)]
use crate::model::ModelController;
pub use self::error::{Error, Result}; pub use self::error::{Error, Result};
use std::net::SocketAddr; use std::net::SocketAddr;
@ -25,10 +27,15 @@ struct HelloParams {
} }
#[tokio::main] #[tokio::main]
async fn main() { async fn main() -> Result<()>{
let mc = ModelController::new().await?;
let routes_apis = web::routes_properties::routes(mc.clone()).route_layer(middleware::from_fn(web::mw_auth::mw_require_auth));
let routes_all = Router::new() let routes_all = Router::new()
.merge(routes_hello()) .merge(routes_hello())
.merge(web::routes_login::routes()) .merge(web::routes_login::routes())
.nest("/api", routes_apis)
.layer(middleware::map_response(main_response_mapper)) .layer(middleware::map_response(main_response_mapper))
.layer(CookieManagerLayer::new()) // must be above? the auth routes .layer(CookieManagerLayer::new()) // must be above? the auth routes
// TODO: continue video at 22:15 // TODO: continue video at 22:15
@ -40,6 +47,8 @@ async fn main() {
.serve(routes_all.into_make_service()) .serve(routes_all.into_make_service())
.await .await
.unwrap(); .unwrap();
Ok(())
} }

View file

@ -1,3 +1,4 @@
pub mod mw_auth;
pub mod routes_login; pub mod routes_login;
pub mod routes_properties; pub mod routes_properties;

42
src/web/mw_auth.rs Normal file
View file

@ -0,0 +1,42 @@
use axum::http::Request;
use axum::middleware::Next;
use axum::response::Response;
use lazy_regex::regex_captures;
use tower_cookies::Cookies;
use crate::web::AUTH_TOKEN;
use crate::{Error, Result};
pub async fn mw_require_auth<B>(
cookies: Cookies,
req: Request<B>,
next: Next<B>
) -> Result<Response> {
println!("->> {:<12} - mw_require_auth", "MIDDLEWARE");
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(next.run(req).await)
}
/// Parse a 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+)\.(.+)\.(.+)"#, // a literal regex
&token)
.ok_or(Error::AuthFailTokenWrongFormat)?;
let user_id: u64 = user_id
.parse()
.map_err(|_| Error::AuthFailTokenWrongFormat)?;
Ok((user_id, exp.to_string(), sign.to_string()))
}

View file

@ -21,7 +21,7 @@ async fn test_quick_dev() -> Result<()> {
json!( json!(
{ {
"username": "demo1", "username": "demo1",
"password": "demo1" "password": "demowrong"
} }
) )
); );
@ -31,7 +31,7 @@ async fn test_quick_dev() -> Result<()> {
json!( json!(
{ {
"username": "demo1", "username": "demo1",
"password": "demowrong" "password": "demo1"
} }
) )
); );
@ -39,5 +39,34 @@ async fn test_quick_dev() -> Result<()> {
hc.do_get("/hello2/mike").await?.print().await?; hc.do_get("/hello2/mike").await?.print().await?;
let req_create_property = hc.do_post(
"/api/properties",
json!(
{
"address": "Lolilat Street 1",
"contact": "01234 567890"
}
)
);
req_create_property.await?.print().await?;
let req_create_property = hc.do_post(
"/api/properties",
json!(
{
"address": "Lolilat Street 2",
"contact": "01243 217890"
}
)
);
req_create_property.await?.print().await?;
let req_get_properties = hc.do_get("/api/properties").await?;
req_get_properties.print().await?;
let req_delete_property = hc.do_delete("/api/properties/1").await?;
req_delete_property.print().await?;
let req_get_properties = hc.do_get("/api/properties").await?;
req_get_properties.print().await?;
let req_delete_property = hc.do_delete("/api/properties/0").await?;
req_delete_property.print().await?;
Ok(()) Ok(())
} }