Auth #169
+71
@@ -156,6 +156,77 @@ pub mod init {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod auth {
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use axum::{
|
||||||
|
http::{Request, StatusCode},
|
||||||
|
middleware::Next,
|
||||||
|
response::{IntoResponse, Response},
|
||||||
|
Json,
|
||||||
|
};
|
||||||
|
use jwt::{Algorithm, VerifyWithKey};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct UserClaims {
|
||||||
|
pub sub: String, // Subject (user ID)
|
||||||
|
pub exp: usize, // Expiration time
|
||||||
|
// Add any additional claims you need
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub async fn auth_middleware<B>(
|
||||||
|
req: axum::http::Request<B>,
|
||||||
|
next: axum::middleware::Next<B>,
|
||||||
|
) -> Result<Response, Response> {
|
||||||
|
// Extract token from header
|
||||||
|
let token = extract_token_from_header(req.headers())
|
||||||
|
.ok_or_else(|| (StatusCode::UNAUTHORIZED, "Missing token").into_response())?;
|
||||||
|
|
||||||
|
// Create HMAC key from your secret
|
||||||
|
let key = jwt::Hmac::new("your-secret-key".as_bytes())
|
||||||
|
.map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Key error").into_response())?;
|
||||||
|
|
||||||
|
// Verify and decode token
|
||||||
|
let claims: BTreeMap<String, String> = token
|
||||||
|
.verify_with_key(&key)
|
||||||
|
.map_err(|_| (StatusCode::UNAUTHORIZED, "Invalid token").into_response())?;
|
||||||
|
|
||||||
|
// Convert to your claims struct
|
||||||
|
let user_claims = serde_json::from_value::<UserClaims>(serde_json::to_value(claims).unwrap())
|
||||||
|
.map_err(|_| (StatusCode::UNAUTHORIZED, "Invalid claims").into_response())?;
|
||||||
|
|
||||||
|
// Check expiration
|
||||||
|
if user_claims.exp < current_timestamp() {
|
||||||
|
return Err((StatusCode::UNAUTHORIZED, "Token expired").into_response());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach claims to request
|
||||||
|
req.extensions_mut().insert(user_claims);
|
||||||
|
|
||||||
|
Ok(next.run(req).await)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to extract token from Authorization header
|
||||||
|
fn extract_token_from_header(headers: &HeaderMap) -> Option<String> {
|
||||||
|
headers
|
||||||
|
.get("Authorization")
|
||||||
|
.and_then(|value| value.to_str().ok())
|
||||||
|
.and_then(|value| value.strip_prefix("Bearer "))
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to get current timestamp
|
||||||
|
fn current_timestamp() -> usize {
|
||||||
|
std::time::SystemTime::now()
|
||||||
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_secs() as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Move elsewhere
|
// TODO: Move elsewhere
|
||||||
fn get_full() -> String {
|
fn get_full() -> String {
|
||||||
get_address() + ":" + &get_port()
|
get_address() + ":" + &get_port()
|
||||||
|
|||||||
Reference in New Issue
Block a user