feat: add API key authentication for /v1/* endpoints

This commit is contained in:
董飞祥
2026-01-13 16:46:31 +08:00
parent d1be2e2c1d
commit 6172f5ef10
4 changed files with 37 additions and 0 deletions

View File

@@ -332,6 +332,7 @@ While most users can use the default settings, you can tune the proxy behavior v
### Configurable Options ### Configurable Options
- **API Key Authentication**: Protect `/v1/*` API endpoints with `API_KEY` env var or `apiKey` in config.
- **WebUI Password**: Secure your dashboard with `WEBUI_PASSWORD` env var or in config. - **WebUI Password**: Secure your dashboard with `WEBUI_PASSWORD` env var or in config.
- **Custom Port**: Change the default `8080` port. - **Custom Port**: Change the default `8080` port.
- **Retry Logic**: Configure `maxRetries`, `retryBaseMs`, and `retryMaxMs`. - **Retry Logic**: Configure `maxRetries`, `retryBaseMs`, and `retryMaxMs`.

View File

@@ -11,6 +11,9 @@
"Restart server after making changes" "Restart server after making changes"
], ],
"apiKey": "",
"_apiKey_comment": "Optional API key to protect /v1/* endpoints. Can also use API_KEY env var.",
"webuiPassword": "", "webuiPassword": "",
"_webuiPassword_comment": "Optional password to protect WebUI. Can also use WEBUI_PASSWORD env var.", "_webuiPassword_comment": "Optional password to protect WebUI. Can also use WEBUI_PASSWORD env var.",

View File

@@ -5,6 +5,7 @@ import { logger } from './utils/logger.js';
// Default config // Default config
const DEFAULT_CONFIG = { const DEFAULT_CONFIG = {
apiKey: '',
webuiPassword: '', webuiPassword: '',
debug: false, debug: false,
logLevel: 'info', logLevel: 'info',
@@ -54,6 +55,7 @@ function loadConfig() {
} }
// Environment overrides // Environment overrides
if (process.env.API_KEY) config.apiKey = process.env.API_KEY;
if (process.env.WEBUI_PASSWORD) config.webuiPassword = process.env.WEBUI_PASSWORD; if (process.env.WEBUI_PASSWORD) config.webuiPassword = process.env.WEBUI_PASSWORD;
if (process.env.DEBUG === 'true') config.debug = true; if (process.env.DEBUG === 'true') config.debug = true;

View File

@@ -65,6 +65,37 @@ async function ensureInitialized() {
app.use(cors()); app.use(cors());
app.use(express.json({ limit: REQUEST_BODY_LIMIT })); app.use(express.json({ limit: REQUEST_BODY_LIMIT }));
// API Key authentication middleware for /v1/* endpoints
app.use('/v1', (req, res, next) => {
// Skip validation if apiKey is not configured
if (!config.apiKey) {
return next();
}
const authHeader = req.headers['authorization'];
const xApiKey = req.headers['x-api-key'];
let providedKey = '';
if (authHeader && authHeader.startsWith('Bearer ')) {
providedKey = authHeader.substring(7);
} else if (xApiKey) {
providedKey = xApiKey;
}
if (!providedKey || providedKey !== config.apiKey) {
logger.warn(`[API] Unauthorized request from ${req.ip}, invalid API key`);
return res.status(401).json({
type: 'error',
error: {
type: 'authentication_error',
message: 'Invalid or missing API key'
}
});
}
next();
});
// Setup usage statistics middleware // Setup usage statistics middleware
usageStats.setupMiddleware(app); usageStats.setupMiddleware(app);