use axum::{ Json, extract::{Request, State}, http::StatusCode, middleware::Next, response::{IntoResponse, Response}, }; use sea_orm::ColumnTrait; use sea_orm::EntityTrait; use sea_orm::QueryFilter; use sha2::{Digest, Sha256}; use uuid::Uuid; use crate::state::HealthState; /// 网关认证上下文 — 中间件注入到请求扩展中 #[derive(Debug, Clone)] pub struct GatewayAuthContext { pub gateway_db_id: Uuid, // ble_gateways 表主键 pub tenant_id: Uuid, pub gateway_id: String, // 物理设备标识 } /// BLE 网关 API Key 认证中间件 /// 请求头: `Authorization: Gateway ` 或 `X-Gateway-Key: ` pub async fn gateway_auth_middleware( State(state): State, mut request: Request, next: Next, ) -> Response { let api_key = extract_gateway_key(&request); let api_key = match api_key { Some(key) => key, None => { return ( StatusCode::UNAUTHORIZED, Json(serde_json::json!({ "success": false, "message": "Missing gateway API key. Use Authorization: Gateway or X-Gateway-Key header" })), ) .into_response(); } }; // 用前 8 位快速定位,再用完整 hash 验证 let prefix = &api_key[..8.min(api_key.len())]; let key_hash = sha256_hex(api_key.as_bytes()); let gateway = crate::entity::ble_gateway::Entity::find() .filter(crate::entity::ble_gateway::Column::ApiKeyPrefix.eq(prefix)) .filter(crate::entity::ble_gateway::Column::ApiKeyHash.eq(&key_hash)) .filter(crate::entity::ble_gateway::Column::DeletedAt.is_null()) .filter(crate::entity::ble_gateway::Column::Status.eq("active")) .one(&state.db) .await; match gateway { Ok(Some(g)) => { let ctx = GatewayAuthContext { gateway_db_id: g.id, tenant_id: g.tenant_id, gateway_id: g.gateway_id.clone(), }; request.extensions_mut().insert(ctx); next.run(request).await } Ok(None) => ( StatusCode::UNAUTHORIZED, Json(serde_json::json!({ "success": false, "message": "Invalid or inactive gateway API key" })), ) .into_response(), Err(e) => { tracing::error!(error = %e, "Gateway auth database error"); ( StatusCode::INTERNAL_SERVER_ERROR, Json(serde_json::json!({ "success": false, "message": "Authentication service error" })), ) .into_response() } } } fn extract_gateway_key(request: &Request) -> Option { // Authorization: Gateway if let Some(auth) = request .headers() .get("Authorization") .and_then(|v| v.to_str().ok()) && let Some(key) = auth.strip_prefix("Gateway ") { let key = key.trim(); if !key.is_empty() { return Some(key.to_string()); } } // X-Gateway-Key: if let Some(key) = request .headers() .get("X-Gateway-Key") .and_then(|v| v.to_str().ok()) { let key = key.trim(); if !key.is_empty() { return Some(key.to_string()); } } None } /// SHA-256 hex digest pub fn sha256_hex(data: &[u8]) -> String { let mut hasher = Sha256::new(); hasher.update(data); let result = hasher.finalize(); hex::encode(result) } /// 生成随机 API Key (32 字节 hex = 64 字符) pub fn generate_api_key() -> (String, String, String) { use rand_core::{OsRng, RngCore}; let mut bytes = [0u8; 32]; OsRng.fill_bytes(&mut bytes); let api_key = hex::encode(bytes); let prefix = api_key[..8].to_string(); let hash = sha256_hex(api_key.as_bytes()); (api_key, prefix, hash) }