feat: align with upstream 1.5.9.9
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
import { apiKeyPermissions, apiKeys, db } from '~/drizzle/db'
|
||||
import { z } from 'zod'
|
||||
import { getBeijingTime } from '~/utils/timeUtils'
|
||||
import { apiPermissionSchema } from './permissions'
|
||||
import { generateApiKey, hashApiKey } from '~~/server/utils/apiKeyUtils'
|
||||
|
||||
/**
|
||||
* 创建API Key
|
||||
* POST /api/admin/api-keys
|
||||
*/
|
||||
|
||||
// 请求体验证schema
|
||||
const createApiKeySchema = z.object({
|
||||
name: z.string().min(1, 'API Key名称不能为空').max(100, 'API Key名称不能超过100个字符'),
|
||||
description: z
|
||||
.union([z.string().max(500, '描述不能超过500个字符'), z.null(), z.undefined()])
|
||||
.optional(),
|
||||
expiresAt: z.union([z.string(), z.null(), z.undefined()]).optional(),
|
||||
|
||||
permissions: z.array(apiPermissionSchema).min(1, '至少需要选择一个权限')
|
||||
})
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
// 检查用户权限 - 只有超级管理员可以管理 API Key
|
||||
const user = event.context.user
|
||||
if (!user || user.role !== 'SUPER_ADMIN') {
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
message: '只有超级管理员可以管理 API Key'
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
// 验证请求体
|
||||
const body = await readBody(event)
|
||||
const validatedData = createApiKeySchema.parse(body)
|
||||
|
||||
// 生成API Key
|
||||
const apiKey = generateApiKey()
|
||||
const keyPrefix = apiKey.substring(0, 10) // vhub_xxxxx
|
||||
const keyHash = await hashApiKey(apiKey)
|
||||
|
||||
// 处理过期时间
|
||||
let expiresAt: Date | null = null
|
||||
if (
|
||||
validatedData.expiresAt &&
|
||||
typeof validatedData.expiresAt === 'string' &&
|
||||
validatedData.expiresAt.trim() !== ''
|
||||
) {
|
||||
try {
|
||||
// 处理预设选项格式 (3d, 7d, 30d, 60d, 90d)
|
||||
if (validatedData.expiresAt.match(/^\d+d$/)) {
|
||||
const days = parseInt(validatedData.expiresAt.replace('d', ''))
|
||||
expiresAt = getBeijingTime()
|
||||
expiresAt.setDate(expiresAt.getDate() + days)
|
||||
} else {
|
||||
// 处理传统的日期时间格式(向后兼容)
|
||||
expiresAt = new Date(validatedData.expiresAt)
|
||||
// 验证日期是否有效
|
||||
if (isNaN(expiresAt.getTime())) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
message: '无效的过期时间格式'
|
||||
})
|
||||
}
|
||||
// 验证过期时间不能是过去的时间
|
||||
if (expiresAt <= getBeijingTime()) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
message: '过期时间不能是过去的时间'
|
||||
})
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
if (error.statusCode) {
|
||||
throw error
|
||||
}
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
message: '无效的过期时间格式'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 开始事务
|
||||
const result = await db.transaction(async (tx) => {
|
||||
// 插入API Key记录
|
||||
const apiKeyResult = await tx
|
||||
.insert(apiKeys)
|
||||
.values({
|
||||
name: validatedData.name,
|
||||
description: validatedData.description || null,
|
||||
keyPrefix,
|
||||
keyHash,
|
||||
isActive: true,
|
||||
expiresAt,
|
||||
|
||||
usageCount: 0,
|
||||
createdByUserId: user.id
|
||||
})
|
||||
.returning({ id: apiKeys.id })
|
||||
|
||||
const createdApiKey = apiKeyResult[0]
|
||||
if (!createdApiKey) {
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
message: '创建 API Key 失败'
|
||||
})
|
||||
}
|
||||
|
||||
const apiKeyId = createdApiKey.id
|
||||
|
||||
// 插入权限记录
|
||||
const permissionValues = validatedData.permissions.map((permission) => ({
|
||||
apiKeyId,
|
||||
permission
|
||||
}))
|
||||
|
||||
await tx.insert(apiKeyPermissions).values(permissionValues)
|
||||
|
||||
return {
|
||||
id: apiKeyId,
|
||||
apiKey,
|
||||
name: validatedData.name,
|
||||
description: validatedData.description,
|
||||
keyPrefix,
|
||||
isActive: true,
|
||||
expiresAt,
|
||||
|
||||
permissions: validatedData.permissions,
|
||||
usageCount: 0,
|
||||
createdBy: user.id,
|
||||
creatorName: user.name
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'API Key创建成功',
|
||||
data: result
|
||||
}
|
||||
} catch (error: any) {
|
||||
if (error.statusCode) {
|
||||
throw error
|
||||
}
|
||||
|
||||
// 处理 Zod 验证错误
|
||||
if (error.name === 'ZodError') {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
message: `请求参数验证失败:${error.errors.map((e: any) => e.message).join(', ')}`
|
||||
})
|
||||
}
|
||||
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
message: `创建 API Key 失败:${error.message}`
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user