fix(gemini): 优化 Gemini 接口认证兼容性,支持 Authorization: Bearer
调整 API key 提取优先级,让 /v1beta 接口同时支持 x-goog-api-key 和 Authorization: Bearer 两种认证方式,解决 OpenClaw 等使用 Bearer 认证 的客户端无法直接访问 Gemini 接口的问题。
This commit is contained in:
@@ -26,7 +26,7 @@ func APIKeyAuthWithSubscriptionGoogle(apiKeyService *service.APIKeyService, subs
|
|||||||
abortWithGoogleError(c, 400, "Query parameter api_key is deprecated. Use Authorization header or key instead.")
|
abortWithGoogleError(c, 400, "Query parameter api_key is deprecated. Use Authorization header or key instead.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
apiKeyString := extractAPIKeyFromRequest(c)
|
apiKeyString := extractAPIKeyForGoogle(c)
|
||||||
if apiKeyString == "" {
|
if apiKeyString == "" {
|
||||||
abortWithGoogleError(c, 401, "API key is required")
|
abortWithGoogleError(c, 401, "API key is required")
|
||||||
return
|
return
|
||||||
@@ -108,25 +108,38 @@ func APIKeyAuthWithSubscriptionGoogle(apiKeyService *service.APIKeyService, subs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractAPIKeyFromRequest(c *gin.Context) string {
|
// extractAPIKeyForGoogle extracts API key for Google/Gemini endpoints.
|
||||||
authHeader := c.GetHeader("Authorization")
|
// Priority: x-goog-api-key > Authorization: Bearer > x-api-key > query key
|
||||||
if authHeader != "" {
|
// This allows OpenClaw and other clients using Bearer auth to work with Gemini endpoints.
|
||||||
parts := strings.SplitN(authHeader, " ", 2)
|
func extractAPIKeyForGoogle(c *gin.Context) string {
|
||||||
if len(parts) == 2 && parts[0] == "Bearer" && strings.TrimSpace(parts[1]) != "" {
|
// 1) preferred: Gemini native header
|
||||||
return strings.TrimSpace(parts[1])
|
if k := strings.TrimSpace(c.GetHeader("x-goog-api-key")); k != "" {
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) fallback: Authorization: Bearer <key>
|
||||||
|
auth := strings.TrimSpace(c.GetHeader("Authorization"))
|
||||||
|
if auth != "" {
|
||||||
|
parts := strings.SplitN(auth, " ", 2)
|
||||||
|
if len(parts) == 2 && strings.EqualFold(parts[0], "Bearer") {
|
||||||
|
if k := strings.TrimSpace(parts[1]); k != "" {
|
||||||
|
return k
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if v := strings.TrimSpace(c.GetHeader("x-api-key")); v != "" {
|
|
||||||
return v
|
// 3) x-api-key header (backward compatibility)
|
||||||
}
|
if k := strings.TrimSpace(c.GetHeader("x-api-key")); k != "" {
|
||||||
if v := strings.TrimSpace(c.GetHeader("x-goog-api-key")); v != "" {
|
return k
|
||||||
return v
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 4) query parameter key (for specific paths)
|
||||||
if allowGoogleQueryKey(c.Request.URL.Path) {
|
if allowGoogleQueryKey(c.Request.URL.Path) {
|
||||||
if v := strings.TrimSpace(c.Query("key")); v != "" {
|
if v := strings.TrimSpace(c.Query("key")); v != "" {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user