mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-22 16:43:35 +00:00
feat: 实现历史API Key自动关联功能
核心功能: - AD用户登录时自动关联已存在的历史API Key - 关联规则: API Key name字段与用户displayName完全匹配 - 自动设置owner字段完成关联,避免用户重新创建Key 实现逻辑: 1. 优先匹配owner字段(已关联的Key) 2. 如无owner匹配,尝试匹配name与displayName 3. 找到匹配历史Key后,自动设置owner完成关联 技术特性: - 详细日志记录关联过程 - 支持JWT token中完整用户信息传递 - Redis数据自动更新owner字段 - 系统迁移兼容性处理 测试验证: - 创建测试历史Key验证自动关联 - JWT token正确解析displayName字段 - Redis数据正确更新owner关联关系 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -384,24 +384,41 @@ const authenticateUser = (req, res, next) => {
|
||||
|
||||
/**
|
||||
* 获取用户的API Keys
|
||||
*
|
||||
* 自动关联逻辑说明:
|
||||
* 系统迁移过程中存在历史API Key,这些Key是在AD集成前手动创建的
|
||||
* 创建时使用的name字段恰好与AD用户的displayName一致
|
||||
* 例如: AD用户displayName为"测试用户",对应的API Key name也是"测试用户"
|
||||
* 为了避免用户重复创建Key,系统会自动关联这些历史Key
|
||||
* 关联规则:
|
||||
* 1. 优先匹配owner字段(新建的Key)
|
||||
* 2. 如果没有owner匹配,则尝试匹配name字段与displayName
|
||||
* 3. 找到匹配的历史Key后,自动将owner设置为当前用户,完成关联
|
||||
*/
|
||||
router.get('/user/api-keys', authenticateUser, async (req, res) => {
|
||||
try {
|
||||
const redis = require('../models/redis')
|
||||
const { username } = req.user
|
||||
const { username, displayName } = req.user
|
||||
|
||||
logger.info(`获取用户API Keys: ${username}`)
|
||||
logger.info(`获取用户API Keys: ${username}, displayName: ${displayName}`)
|
||||
logger.info(`用户完整信息: ${JSON.stringify(req.user)}`)
|
||||
|
||||
// 获取所有API Keys
|
||||
const allKeysPattern = 'api_key:*'
|
||||
const keys = await redis.getClient().keys(allKeysPattern)
|
||||
|
||||
const userKeys = []
|
||||
let foundHistoricalKey = false
|
||||
|
||||
// 筛选属于该用户的API Keys
|
||||
for (const key of keys) {
|
||||
const apiKeyData = await redis.getClient().hgetall(key)
|
||||
if (apiKeyData && apiKeyData.owner === username) {
|
||||
if (!apiKeyData) {
|
||||
continue
|
||||
}
|
||||
|
||||
// 规则1: 直接owner匹配(已关联的Key)
|
||||
if (apiKeyData.owner === username) {
|
||||
userKeys.push({
|
||||
id: apiKeyData.id,
|
||||
name: apiKeyData.name || '未命名',
|
||||
@@ -412,6 +429,30 @@ router.get('/user/api-keys', authenticateUser, async (req, res) => {
|
||||
status: apiKeyData.status || 'active'
|
||||
})
|
||||
}
|
||||
// 规则2: 历史Key自动关联(name字段匹配displayName且无owner)
|
||||
else if (displayName && apiKeyData.name === displayName && !apiKeyData.owner) {
|
||||
logger.info(`发现历史API Key需要关联: name=${apiKeyData.name}, displayName=${displayName}`)
|
||||
|
||||
// 自动关联: 设置owner为当前用户
|
||||
await redis.getClient().hset(key, 'owner', username)
|
||||
foundHistoricalKey = true
|
||||
|
||||
userKeys.push({
|
||||
id: apiKeyData.id,
|
||||
name: apiKeyData.name || '未命名',
|
||||
key: apiKeyData.key,
|
||||
limit: parseInt(apiKeyData.limit) || 1000000,
|
||||
used: parseInt(apiKeyData.used) || 0,
|
||||
createdAt: apiKeyData.createdAt,
|
||||
status: apiKeyData.status || 'active'
|
||||
})
|
||||
|
||||
logger.info(`历史API Key关联成功: ${apiKeyData.id} -> ${username}`)
|
||||
}
|
||||
}
|
||||
|
||||
if (foundHistoricalKey) {
|
||||
logger.info(`用户 ${username} 自动关联了历史API Key`)
|
||||
}
|
||||
|
||||
res.json({
|
||||
|
||||
Reference in New Issue
Block a user