mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-22 16:43:35 +00:00
feat: 适配新版本gemini
This commit is contained in:
@@ -65,6 +65,44 @@ const TOKEN_COUNT_PATHS = new Set([
|
|||||||
'/droid/claude/v1/messages/count_tokens'
|
'/droid/claude/v1/messages/count_tokens'
|
||||||
])
|
])
|
||||||
|
|
||||||
|
function extractApiKey(req) {
|
||||||
|
const candidates = [
|
||||||
|
req.headers['x-api-key'],
|
||||||
|
req.headers['x-goog-api-key'],
|
||||||
|
req.headers['authorization'],
|
||||||
|
req.headers['api-key'],
|
||||||
|
req.query?.key
|
||||||
|
]
|
||||||
|
|
||||||
|
for (const candidate of candidates) {
|
||||||
|
let value = candidate
|
||||||
|
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
value = value.find((item) => typeof item === 'string' && item.trim())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value !== 'string') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
let trimmed = value.trim()
|
||||||
|
if (!trimmed) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/^Bearer\s+/i.test(trimmed)) {
|
||||||
|
trimmed = trimmed.replace(/^Bearer\s+/i, '').trim()
|
||||||
|
if (!trimmed) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return trimmed
|
||||||
|
}
|
||||||
|
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeRequestPath(value) {
|
function normalizeRequestPath(value) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return '/'
|
return '/'
|
||||||
@@ -95,18 +133,18 @@ const authenticateApiKey = async (req, res, next) => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// 安全提取API Key,支持多种格式(包括Gemini CLI支持)
|
// 安全提取API Key,支持多种格式(包括Gemini CLI支持)
|
||||||
const apiKey =
|
const apiKey = extractApiKey(req)
|
||||||
req.headers['x-api-key'] ||
|
|
||||||
req.headers['x-goog-api-key'] ||
|
if (apiKey) {
|
||||||
req.headers['authorization']?.replace(/^Bearer\s+/i, '') ||
|
req.headers['x-api-key'] = apiKey
|
||||||
req.headers['api-key'] ||
|
}
|
||||||
req.query.key
|
|
||||||
|
|
||||||
if (!apiKey) {
|
if (!apiKey) {
|
||||||
logger.security(`🔒 Missing API key attempt from ${req.ip || 'unknown'}`)
|
logger.security(`🔒 Missing API key attempt from ${req.ip || 'unknown'}`)
|
||||||
return res.status(401).json({
|
return res.status(401).json({
|
||||||
error: 'Missing API key',
|
error: 'Missing API key',
|
||||||
message: 'Please provide an API key in the x-api-key header or Authorization header'
|
message:
|
||||||
|
'Please provide an API key in the x-api-key, x-goog-api-key, or Authorization header'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -950,6 +988,7 @@ const corsMiddleware = (req, res, next) => {
|
|||||||
'Accept',
|
'Accept',
|
||||||
'Authorization',
|
'Authorization',
|
||||||
'x-api-key',
|
'x-api-key',
|
||||||
|
'x-goog-api-key',
|
||||||
'api-key',
|
'api-key',
|
||||||
'x-admin-token',
|
'x-admin-token',
|
||||||
'anthropic-version',
|
'anthropic-version',
|
||||||
|
|||||||
@@ -7,12 +7,38 @@ const logger = require('../utils/logger')
|
|||||||
const browserFallbackMiddleware = (req, res, next) => {
|
const browserFallbackMiddleware = (req, res, next) => {
|
||||||
const userAgent = req.headers['user-agent'] || ''
|
const userAgent = req.headers['user-agent'] || ''
|
||||||
const origin = req.headers['origin'] || ''
|
const origin = req.headers['origin'] || ''
|
||||||
const authHeader = req.headers['authorization'] || req.headers['x-api-key'] || ''
|
|
||||||
|
const extractHeader = (value) => {
|
||||||
|
let candidate = value
|
||||||
|
|
||||||
|
if (Array.isArray(candidate)) {
|
||||||
|
candidate = candidate.find((item) => typeof item === 'string' && item.trim())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof candidate !== 'string') {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
let trimmed = candidate.trim()
|
||||||
|
if (!trimmed) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/^Bearer\s+/i.test(trimmed)) {
|
||||||
|
trimmed = trimmed.replace(/^Bearer\s+/i, '').trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
return trimmed
|
||||||
|
}
|
||||||
|
|
||||||
|
const apiKeyHeader =
|
||||||
|
extractHeader(req.headers['x-api-key']) || extractHeader(req.headers['x-goog-api-key'])
|
||||||
|
const normalizedKey = extractHeader(req.headers['authorization']) || apiKeyHeader
|
||||||
|
|
||||||
// 检查是否为Chrome插件或浏览器请求
|
// 检查是否为Chrome插件或浏览器请求
|
||||||
const isChromeExtension = origin.startsWith('chrome-extension://')
|
const isChromeExtension = origin.startsWith('chrome-extension://')
|
||||||
const isBrowserRequest = userAgent.includes('Mozilla/') && userAgent.includes('Chrome/')
|
const isBrowserRequest = userAgent.includes('Mozilla/') && userAgent.includes('Chrome/')
|
||||||
const hasApiKey = authHeader.startsWith('cr_') // 我们的API Key格式
|
const hasApiKey = normalizedKey.startsWith('cr_') // 我们的API Key格式
|
||||||
|
|
||||||
if ((isChromeExtension || isBrowserRequest) && hasApiKey) {
|
if ((isChromeExtension || isBrowserRequest) && hasApiKey) {
|
||||||
// 为Chrome插件请求添加特殊标记
|
// 为Chrome插件请求添加特殊标记
|
||||||
@@ -23,8 +49,8 @@ const browserFallbackMiddleware = (req, res, next) => {
|
|||||||
req.headers['user-agent'] = 'claude-cli/1.0.110 (external, cli, browser-fallback)'
|
req.headers['user-agent'] = 'claude-cli/1.0.110 (external, cli, browser-fallback)'
|
||||||
|
|
||||||
// 确保设置正确的认证头
|
// 确保设置正确的认证头
|
||||||
if (!req.headers['authorization'] && req.headers['x-api-key']) {
|
if (!req.headers['authorization'] && apiKeyHeader) {
|
||||||
req.headers['authorization'] = `Bearer ${req.headers['x-api-key']}`
|
req.headers['authorization'] = `Bearer ${apiKeyHeader}`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加必要的Anthropic头
|
// 添加必要的Anthropic头
|
||||||
|
|||||||
@@ -13,13 +13,10 @@ const { updateRateLimitCounters } = require('../utils/rateLimitHelper')
|
|||||||
|
|
||||||
// 生成会话哈希
|
// 生成会话哈希
|
||||||
function generateSessionHash(req) {
|
function generateSessionHash(req) {
|
||||||
const sessionData = [
|
const apiKeyPrefix =
|
||||||
req.headers['user-agent'],
|
req.headers['x-api-key']?.substring(0, 10) || req.headers['x-goog-api-key']?.substring(0, 10)
|
||||||
req.ip,
|
|
||||||
req.headers['x-api-key']?.substring(0, 10)
|
const sessionData = [req.headers['user-agent'], req.ip, apiKeyPrefix].filter(Boolean).join(':')
|
||||||
]
|
|
||||||
.filter(Boolean)
|
|
||||||
.join(':')
|
|
||||||
|
|
||||||
return crypto.createHash('sha256').update(sessionData).digest('hex')
|
return crypto.createHash('sha256').update(sessionData).digest('hex')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,10 @@ const crypto = require('crypto')
|
|||||||
|
|
||||||
// 生成会话哈希
|
// 生成会话哈希
|
||||||
function generateSessionHash(req) {
|
function generateSessionHash(req) {
|
||||||
const sessionData = [
|
const authSource =
|
||||||
req.headers['user-agent'],
|
req.headers['authorization'] || req.headers['x-api-key'] || req.headers['x-goog-api-key']
|
||||||
req.ip,
|
|
||||||
req.headers['authorization']?.substring(0, 20)
|
const sessionData = [req.headers['user-agent'], req.ip, authSource?.substring(0, 20)]
|
||||||
]
|
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join(':')
|
.join(':')
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user