/** * 请求认证中间件 * 验证客户端请求的 API Key,保护 API 端点 */ import { getConfig } from './config.js'; import { logInfo, logError } from './logger.js'; // 不需要认证的路径(精确匹配) const PUBLIC_PATHS = new Set([ '/', '/health', '/status' ]); // 可配置是否公开的路径 const OPTIONAL_PUBLIC_PATHS = new Set([ '/v1/models' ]); /** * 获取认证配置 * API Keys 只从环境变量读取(安全考虑) * enabled/public_models 可从 config.json 读取默认值,环境变量可覆盖 */ export function getAuthConfig() { const cfg = getConfig(); const configAuth = cfg.auth || {}; // 环境变量 const envEnabled = process.env.AUTH_ENABLED; const envApiKeys = process.env.API_KEYS; const envPublicModels = process.env.AUTH_PUBLIC_MODELS; // 解析 enabled(环境变量 > config.json) let enabled = configAuth.enabled ?? false; if (envEnabled !== undefined) { enabled = ['true', '1', 'yes'].includes(envEnabled.toLowerCase()); } // API Keys 只从环境变量读取(敏感信息不应存储在配置文件中) let apiKeys = []; if (envApiKeys) { apiKeys = envApiKeys.split(',').map(k => k.trim()).filter(k => k); } // 解析 public_models(环境变量 > config.json) let publicModels = configAuth.public_models ?? true; if (envPublicModels !== undefined) { publicModels = ['true', '1', 'yes'].includes(envPublicModels.toLowerCase()); } return { enabled, apiKeys: new Set(apiKeys), publicModels }; } /** * 从请求头中提取 API Key * 支持: Authorization: Bearer 或 x-api-key: */ function extractApiKey(req) { // 优先检查 Authorization header const authHeader = req.headers.authorization; if (authHeader) { if (authHeader.startsWith('Bearer ')) { return authHeader.slice(7).trim(); } // 也支持直接传 key(不带 Bearer 前缀) return authHeader.trim(); } // 其次检查 x-api-key header const xApiKey = req.headers['x-api-key']; if (xApiKey) { return xApiKey.trim(); } return null; } /** * 认证中间件 */ export function authMiddleware(req, res, next) { const authConfig = getAuthConfig(); // 如果认证未启用,直接放行 if (!authConfig.enabled) { return next(); } // 检查是否是公开路径 if (PUBLIC_PATHS.has(req.path)) { return next(); } // 检查可选公开路径 if (authConfig.publicModels && OPTIONAL_PUBLIC_PATHS.has(req.path)) { return next(); } // 检查 API Keys 是否配置 if (authConfig.apiKeys.size === 0) { logError('Auth enabled but no API keys configured'); return res.status(500).json({ error: { message: 'Server configuration error: authentication enabled but no API keys configured', type: 'server_error', code: 'auth_not_configured' } }); } // 提取并验证 API Key const clientKey = extractApiKey(req); if (!clientKey) { logInfo(`Auth failed: No API key provided for ${req.method} ${req.path}`); return res.status(401).json({ error: { message: 'Missing API key. Please include your API key in the Authorization header using Bearer auth (Authorization: Bearer YOUR_API_KEY) or as x-api-key header.', type: 'authentication_error', code: 'missing_api_key' } }); } if (!authConfig.apiKeys.has(clientKey)) { logInfo(`Auth failed: Invalid API key for ${req.method} ${req.path}`); return res.status(401).json({ error: { message: 'Invalid API key provided.', type: 'authentication_error', code: 'invalid_api_key' } }); } // 认证通过 next(); } export default authMiddleware;