token tester for login provided token

This commit is contained in:
2025-09-23 16:56:56 +02:00
parent 7b6b735b87
commit af03bd4e31
2 changed files with 66 additions and 110 deletions

View File

@@ -1,75 +1,87 @@
use std::time::Duration;
use axum::{
body::{to_bytes, Body},
http::{Request as HttpRequest, StatusCode},
http::{Request as HttpRequest, StatusCode, },
http::request::Parts,
middleware::Next,
response::{Response, IntoResponse},
Json,
extract::{Path, State, FromRequest}
extract::{Path, State, FromRequest, FromRequestParts}
};
use axum::extract::FromRef;
use axum::extract::Request as ExtractRequest;
use jsonwebtoken::{decode, DecodingKey, Validation, encode, EncodingKey, Header};
use jsonwebtoken::{decode, DecodingKey, Validation, encode, EncodingKey, Header, Algorithm};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use chrono::{Utc};
use rusqlite::{params, Connection, OptionalExtension};
use async_trait::async_trait;
use rand_core::OsRng;
use argon2::{
password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
Argon2};
//use crate::utils::db_pool::;
use crate::utils::db_pool::{HotelPool,AppState};
use rand_core::OsRng;
use argon2::{
password_hash::{
PasswordHash, PasswordHasher, PasswordVerifier, SaltString
},
Argon2
};
pub async fn auth_middleware(
mut req: HttpRequest<Body>,
next: Next,
) -> Result<Response, StatusCode> {
// buffer body
let body = std::mem::take(req.body_mut());
// Buffer into bytes
let bytes = to_bytes(body, 1024 * 1024)
.await
.map_err(|_| StatusCode::BAD_REQUEST)?;
// parse JSON as generic `Value`
let value: Value = serde_json::from_slice(&bytes)
.map_err(|_| StatusCode::BAD_REQUEST)?;
// pull out token
let token = value
.get("token")
.and_then(|t| t.as_str())
.ok_or(StatusCode::UNAUTHORIZED)?;
// verify token
let key = DecodingKey::from_secret("your_jwt_secret_key".as_ref());
let validation = Validation::default();
let claims = decode::<Claims>(token, &key, &validation)
.map_err(|_| StatusCode::UNAUTHORIZED)?
.claims;
// inject claims for downstream handlers
req.extensions_mut().insert(claims);
// restore the original body so the handler can parse it into *its own* struct
req = req.map(|_| Body::from(bytes));
Ok(next.run(req).await)
pub async fn token_tester(
State(state): State<AppState>,
AuthClaims { user_id, hotel_id, username }: AuthClaims,
) -> impl IntoResponse {
format!(
"Hello {} (user_id: {}) from hotel {}",
username, user_id, hotel_id
)
}
pub struct AuthUser(pub Claims); //??
#[derive(Debug, Clone)]
pub struct AuthClaims {
pub user_id: i32,
pub hotel_id: i32,
pub username: String,
}
impl<S> FromRequestParts<S> for AuthClaims
where
S: Send + Sync + 'static,
AppState: Clone + Send + Sync + 'static, AppState: FromRef<S>
{
type Rejection = (StatusCode, String);
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
// We assume your state has a `jwt_secret` field
// 1⃣ Extract the token from the Authorization header
let auth_header = parts
.headers
.get("Authorization")
.ok_or((StatusCode::UNAUTHORIZED, "Missing Authorization header".to_string()))?
.to_str()
.map_err(|_| (StatusCode::BAD_REQUEST, "Invalid Authorization header".to_string()))?;
// Bearer token?
let token = auth_header
.strip_prefix("Bearer ")
.ok_or((StatusCode::BAD_REQUEST, "Expected Bearer token".to_string()))?;
// 2⃣ Decode the token
let token_data = decode::<Claims>(
token,
&DecodingKey::from_secret("your_jwt_secret_key s".to_string().as_ref()),
&Validation::new(Algorithm::HS256),
).map_err(|_| (StatusCode::UNAUTHORIZED, "Invalid token".to_string()))?;
Ok(AuthClaims {
user_id: token_data.claims.id,
hotel_id: token_data.claims.hotel_id,
username: token_data.claims.username,
})
}
}
// Hash a new password
fn hash_password(password: &str) -> anyhow::Result<String> {
@@ -172,63 +184,6 @@ struct LoginResponse {
token: String,
}
//pub async fn auth_register();
/*
pub async fn auth_loggin(
// State(hotel_pools): State<HotelPools>,
LoginPayload(payload): LoginPayload,
) -> impl IntoResponse {
let pool = .get_pool(payload.hotel_id);
let conn = pool.get().unwrap();
/*
let conn = match pool.get() {
Ok(conn) => conn,
Err(err) => return (StatusCode::INTERNAL_SERVER_ERROR, format!("Pool error: {err}")),
};
*/
let mut statement = conn
.prepare("SELECT id, displayname, hotel_id FROM users WHERE username = ? 1 AND password = ?2 ")
.unwrap();
let user_row = statement
.query_row(params![&payload.username, &payload.password], |row| {
let id: i32 = row.get(0)?;
let displayname: String = row.get(1)?;
let hotel_id: i32 = row.get(2)?;
Ok((id, displayname, hotel_id))
})
.optional()
.unwrap(); // returns Ok(Some(...)) or Ok(None)
if let Some((id, displayname, hotel_id)) = user_row {
let expiration = chrono::Utc::now()
.checked_add_signed(chrono::Duration::minutes(15))
.unwrap()
.timestamp() as usize;
let claims = Claims {
id,
hotel_id,
username: displayname, // or payload.username if you prefer
exp: expiration,
};
let token = encode(
&Header::default(),
&claims,
&EncodingKey::from_secret("TEST".as_bytes()),
)
.unwrap();
return (StatusCode::OK, Json(LoginResponse { token }));
}
// Fallback if login failed — wrap String in Json<LoginResponse> or use axum::Json
return (StatusCode::UNAUTHORIZED, Json(LoginResponse { token: "".to_string() }));
}
*/
pub async fn clean_auth_loging(
State(state): State<AppState>,
LoginPayload(payload): LoginPayload

View File

@@ -4,7 +4,7 @@ use axum::{
};
use crate::utils::auth::*;
use crate::utils::db_pool::{HotelPool, AppState};
use crate::utils::db_pool::{HotelPool, AppState, };
// ROOTS
@@ -13,5 +13,6 @@ pub fn utils_routes() -> Router<AppState> {
Router::new()
.route("/login", put(clean_auth_loging))
.route("/register", put(register_user))
.route("/tokentest", put(token_tester))
//.with_state(state)
}