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
|
||||
fn get_full() -> String {
|
||||
get_address() + ":" + &get_port()
|
||||
|
||||
Reference in New Issue
Block a user