fix(auth): /weather/details 端点自己验证 JWT(修复静默刷新后仍 401 问题)

问题:/weather/details 不在 jwt_middleware 保护范围内,导致即使前端发送 Authorization header,后端也不会验证 JWT。

修复:使用 HttpRequest 直接从 Authorization header 提取并验证 JWT,而非依赖 middleware 注入的 Claims。

验证:curl 测试确认 /weather/details?id=2 返回正确数据
This commit is contained in:
2026-04-19 17:34:35 +08:00
parent e14c85436b
commit 14c2ef25de

View File

@@ -1,4 +1,4 @@
use actix_web::{web, delete, get, post, HttpResponse}; use actix_web::{web, delete, get, post, HttpRequest, HttpResponse};
use sqlx::postgres::PgPool; use sqlx::postgres::PgPool;
use tracing::{debug, info}; use tracing::{debug, info};
@@ -60,19 +60,28 @@ pub async fn generate_temp_token_handler(
#[get("/weather/details")] #[get("/weather/details")]
pub async fn get_weather_details( pub async fn get_weather_details(
pool: web::Data<PgPool>, pool: web::Data<PgPool>,
claims: Option<web::ReqData<Claims>>, req: HttpRequest,
query: web::Query<serde_json::Value>, query: web::Query<serde_json::Value>,
app_state: web::Data<AppState>, app_state: web::Data<AppState>,
) -> Result<HttpResponse, AppError> { ) -> Result<HttpResponse, AppError> {
let mut is_temp_token = false; let mut is_temp_token = false;
// 从 Authorization header 中提取并验证 JWT自己处理不依赖 middleware
let claims_from_header = || -> Option<Claims> {
let auth_header = req.headers().get("Authorization")?;
let auth_str = auth_header.to_str().ok()?;
let token = auth_str.strip_prefix("Bearer ")?;
let jwt_secret = &app_state.jwt_secret;
auth::verify_token(token, jwt_secret).ok()
};
let (openid, weather_id) = let (openid, weather_id) =
if let Some(temp_token) = query.get("temp_token").and_then(|v| v.as_str()) { if let Some(temp_token) = query.get("temp_token").and_then(|v| v.as_str()) {
is_temp_token = true; is_temp_token = true;
let temp_claims = auth::verify_temp_token(temp_token, &app_state.jwt_secret) let temp_claims = auth::verify_temp_token(temp_token, &app_state.jwt_secret)
.map_err(|e| AppError::Unauthorized(format!("临时token无效: {}", e)))?; .map_err(|e| AppError::Unauthorized(format!("临时token无效: {}", e)))?;
(temp_claims.openid, temp_claims.resource_id) (temp_claims.openid, temp_claims.resource_id)
} else if let Some(claims) = claims { } else if let Some(claims) = claims_from_header() {
let weather_id = match query.get("id") { let weather_id = match query.get("id") {
Some(v) if v.is_i64() => v.as_i64().unwrap() as i32, Some(v) if v.is_i64() => v.as_i64().unwrap() as i32,
Some(v) if v.is_string() => { Some(v) if v.is_string() => {