use axum::{
extract::Request,
http::{HeaderMap, StatusCode},
middleware::Next,
response::Response,
};
pub struct ApiKeyAuth {
api_key: Option<String>,
}
impl ApiKeyAuth {
pub fn new(api_key: Option<String>) -> Self {
Self { api_key }
}
pub fn is_enabled(&self) -> bool {
self.api_key.is_some()
}
pub fn validate(&self, key: &str) -> bool {
match &self.api_key {
Some(expected) => expected == key,
None => true, }
}
}
pub async fn auth_middleware(
headers: HeaderMap,
request: Request,
next: Next,
) -> Result<Response, StatusCode> {
if let Some(auth_header) = headers.get("Authorization") {
if let Ok(auth_str) = auth_header.to_str() {
let key = if auth_str.starts_with("Bearer ") {
&auth_str[7..]
} else {
auth_str
};
if !key.is_empty() {
return Ok(next.run(request).await);
}
}
}
Ok(next.run(request).await)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_api_key_auth_disabled() {
let auth = ApiKeyAuth::new(None);
assert!(!auth.is_enabled());
assert!(auth.validate("any_key"));
}
#[test]
fn test_api_key_auth_enabled() {
let auth = ApiKeyAuth::new(Some("secret123".to_string()));
assert!(auth.is_enabled());
assert!(auth.validate("secret123"));
assert!(!auth.validate("wrong_key"));
}
#[test]
fn test_api_key_validation() {
let auth = ApiKeyAuth::new(Some("my-secret-key".to_string()));
assert!(auth.validate("my-secret-key"));
assert!(!auth.validate(""));
assert!(!auth.validate("wrong"));
}
}