feat: 添加API Key并发控制和编辑功能

- 新增API Key并发控制功能
  - 创建API Key时可设置并发限制(0为不限制)
  - 在认证中间件中实现并发检查
  - 使用Redis原子操作确保计数准确
  - 添加自动清理机制处理异常情况

- 新增API Key编辑功能
  - 支持修改Token限制和并发限制
  - 前端添加编辑按钮和模态框
  - 后端限制只能修改指定字段

- 其他改进
  - 添加test-concurrency.js测试脚本
  - 添加详细的功能说明文档
  - 所有代码通过ESLint检查

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
shaw
2025-07-16 09:45:47 +08:00
parent efa7048018
commit 12b41ceb25
9 changed files with 654 additions and 15 deletions

View File

@@ -32,7 +32,8 @@ router.post('/api-keys', authenticateAdmin, async (req, res) => {
tokenLimit,
requestLimit,
expiresAt,
claudeAccountId
claudeAccountId,
concurrencyLimit
} = req.body;
// 输入验证
@@ -56,13 +57,18 @@ router.post('/api-keys', authenticateAdmin, async (req, res) => {
return res.status(400).json({ error: 'Request limit must be a non-negative integer' });
}
if (concurrencyLimit !== undefined && concurrencyLimit !== null && concurrencyLimit !== '' && (!Number.isInteger(Number(concurrencyLimit)) || Number(concurrencyLimit) < 0)) {
return res.status(400).json({ error: 'Concurrency limit must be a non-negative integer' });
}
const newKey = await apiKeyService.generateApiKey({
name,
description,
tokenLimit,
requestLimit,
expiresAt,
claudeAccountId
claudeAccountId,
concurrencyLimit
});
logger.success(`🔑 Admin created new API key: ${name}`);
@@ -77,7 +83,24 @@ router.post('/api-keys', authenticateAdmin, async (req, res) => {
router.put('/api-keys/:keyId', authenticateAdmin, async (req, res) => {
try {
const { keyId } = req.params;
const updates = req.body;
const { tokenLimit, concurrencyLimit } = req.body;
// 只允许更新tokenLimit和concurrencyLimit
const updates = {};
if (tokenLimit !== undefined && tokenLimit !== null && tokenLimit !== '') {
if (!Number.isInteger(Number(tokenLimit)) || Number(tokenLimit) < 0) {
return res.status(400).json({ error: 'Token limit must be a non-negative integer' });
}
updates.tokenLimit = Number(tokenLimit);
}
if (concurrencyLimit !== undefined && concurrencyLimit !== null && concurrencyLimit !== '') {
if (!Number.isInteger(Number(concurrencyLimit)) || Number(concurrencyLimit) < 0) {
return res.status(400).json({ error: 'Concurrency limit must be a non-negative integer' });
}
updates.concurrencyLimit = Number(concurrencyLimit);
}
await apiKeyService.updateApiKey(keyId, updates);