fix: P0+P1 security and quality fixes

P0-1: Token refresh race condition — reject all pending requests on refresh failure
P0-2: Remove X-Forwarded-For trust in rate limiting — use only ConnectInfo IP
P1-3: Template grid reactive — use useSaaSStore() hook instead of getState()
P1-4: Agent Template detail modal — show emoji, personality, soul_content, welcome_message,
      communication_style, source_id, scenarios, version
P1-5: adminRouting parse validation — type-safe llm_routing extraction from localStorage
P1-6: Remove unused @ant-design/charts dependency
P1-extra: Type addKeyMutation data parameter (replace any)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
iven
2026-03-31 09:17:04 +08:00
parent 49abd0fe89
commit 1d9283f335
7 changed files with 79 additions and 1401 deletions

View File

@@ -129,18 +129,13 @@ pub async fn public_rate_limit_middleware(
"public_rate_limit", "请求频率超限,请稍后再试")
};
// 从连接信息或 header 提取客户端 IP
// 从连接信息提取客户端 IP
// 安全策略: 仅使用 TCP 连接层 IP不信任 X-Forwarded-For / X-Real-IP 头
// 反向代理场景下应使用 ConnectInfo<SocketAddr> 或在代理层做限流
let client_ip = req.extensions()
.get::<axum::extract::ConnectInfo<std::net::SocketAddr>>()
.map(|ci| ci.0.ip().to_string())
.unwrap_or_else(|| {
req.headers()
.get("x-real-ip")
.or_else(|| req.headers().get("x-forwarded-for"))
.and_then(|v| v.to_str().ok())
.map(|s| s.split(',').next().unwrap_or("unknown").trim().to_string())
.unwrap_or_else(|| "unknown".to_string())
});
.unwrap_or_else(|| "unknown".to_string());
let key = format!("{}:{}", key_prefix, client_ip);
let now = Instant::now();