From 29cbf524e959ab713dbcbae36fdce179c9688870 Mon Sep 17 00:00:00 2001 From: cc Date: Wed, 24 Jun 2026 21:08:42 +0800 Subject: [PATCH] feat(routes): AuthUser extractor validating Bearer JWT Co-Authored-By: Claude Opus 4.8 --- Server/src/routes/extract.rs | 30 ++++++++++++++++++++++++++++++ Server/src/routes/mod.rs | 1 + 2 files changed, 31 insertions(+) create mode 100644 Server/src/routes/extract.rs diff --git a/Server/src/routes/extract.rs b/Server/src/routes/extract.rs new file mode 100644 index 0000000..42052d4 --- /dev/null +++ b/Server/src/routes/extract.rs @@ -0,0 +1,30 @@ +//! 鉴权提取器:从 `Authorization: Bearer ` 解出当前用户名。 +//! +//! axum 0.8 的 `FromRequestParts` 用原生 `async fn`,无需 `#[async_trait]`。 + +use axum::extract::FromRequestParts; +use axum::http::{header, request::Parts, StatusCode}; + +use crate::auth; + +/// 受保护接口的参数:产出已校验的用户名;缺失/非法/过期 token 一律 `401`。 +pub struct AuthUser(pub String); + +impl FromRequestParts for AuthUser +where + S: Send + Sync, +{ + type Rejection = StatusCode; + + async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result { + let header = parts + .headers + .get(header::AUTHORIZATION) + .and_then(|v| v.to_str().ok()) + .ok_or(StatusCode::UNAUTHORIZED)?; + let token = header.strip_prefix("Bearer ").ok_or(StatusCode::UNAUTHORIZED)?; + auth::verify_token(token) + .map(AuthUser) + .ok_or(StatusCode::UNAUTHORIZED) + } +} diff --git a/Server/src/routes/mod.rs b/Server/src/routes/mod.rs index d701bdb..1dfa013 100644 --- a/Server/src/routes/mod.rs +++ b/Server/src/routes/mod.rs @@ -9,6 +9,7 @@ //! 可用环境变量 `STATIC_DIR` 覆盖。 mod client; +mod extract; mod web; use axum::Router;