fix: 修复 /v1/messages 端点返回 Anthropic 标准错误格式

- 新增 verify_api_key_anthropic 函数,返回 Anthropic 标准错误格式
- 更新 /v1/messages、/:selector/v1/messages、/api/provider/:provider/v1/messages 端点使用新认证函数
- 优先检查 x-api-key header(Anthropic 标准)
- 错误响应格式: {"type": "error", "error": {"type": "authentication_error", "message": "..."}}

Fixes #3
This commit is contained in:
coso
2025-12-18 01:11:55 +08:00
parent a504ec88fb
commit 816d293631
6 changed files with 53 additions and 6 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "proxycast",
"private": true,
"version": "0.12.0",
"version": "0.12.1",
"type": "module",
"scripts": {
"dev": "vite",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "proxycast"
version = "0.12.0"
version = "0.12.1"
description = "AI API Proxy Desktop App"
authors = ["you"]
edition = "2021"
+50 -3
View File
@@ -877,6 +877,50 @@ async fn verify_api_key(
Ok(())
}
/// Anthropic 格式的 API key 验证
/// 返回 Anthropic 标准错误格式:{"type": "error", "error": {"type": "...", "message": "..."}}
async fn verify_api_key_anthropic(
headers: &HeaderMap,
expected_key: &str,
) -> Result<(), (StatusCode, Json<serde_json::Value>)> {
let auth = headers
.get("x-api-key")
.or_else(|| headers.get("authorization"))
.and_then(|v| v.to_str().ok());
let key = match auth {
Some(s) if s.starts_with("Bearer ") => &s[7..],
Some(s) => s,
None => {
return Err((
StatusCode::UNAUTHORIZED,
Json(serde_json::json!({
"type": "error",
"error": {
"type": "authentication_error",
"message": "No API key provided. Please set the x-api-key header."
}
})),
))
}
};
if key != expected_key {
return Err((
StatusCode::UNAUTHORIZED,
Json(serde_json::json!({
"type": "error",
"error": {
"type": "authentication_error",
"message": "Invalid API key"
}
})),
));
}
Ok(())
}
async fn chat_completions(
State(state): State<AppState>,
headers: HeaderMap,
@@ -1293,7 +1337,8 @@ async fn anthropic_messages(
headers: HeaderMap,
Json(mut request): Json<AnthropicMessagesRequest>,
) -> Response {
if let Err(e) = verify_api_key(&headers, &state.api_key).await {
// 使用 Anthropic 格式的认证验证(优先检查 x-api-key)
if let Err(e) = verify_api_key_anthropic(&headers, &state.api_key).await {
state
.logs
.write()
@@ -2276,7 +2321,8 @@ async fn anthropic_messages_with_selector(
headers: HeaderMap,
Json(request): Json<AnthropicMessagesRequest>,
) -> Response {
if let Err(e) = verify_api_key(&headers, &state.api_key).await {
// 使用 Anthropic 格式的认证验证
if let Err(e) = verify_api_key_anthropic(&headers, &state.api_key).await {
state.logs.write().await.add(
"warn",
&format!("Unauthorized request to /{}/v1/messages", selector),
@@ -2523,7 +2569,8 @@ async fn amp_messages(
headers: HeaderMap,
Json(mut request): Json<AnthropicMessagesRequest>,
) -> Response {
if let Err(e) = verify_api_key(&headers, &state.api_key).await {
// 使用 Anthropic 格式的认证验证
if let Err(e) = verify_api_key_anthropic(&headers, &state.api_key).await {
state.logs.write().await.add(
"warn",
&format!(
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "ProxyCast",
"version": "0.12.0",
"version": "0.12.1",
"identifier": "com.proxycast.app",
"build": {
"beforeDevCommand": "npm run dev",