import { createHash, randomBytes } from 'crypto'; import type { PrismaClient as ProjectPrismaClient } from '.prisma/project-client'; type ApiKeyPrismaClient = Pick; /** * 生成新的 API Key * 返回原始 key(只显示一次)和哈希值(存储用) */ export function generateApiKey(): { key: string; hash: string } { // 生成 32 字节随机数,转为 base64,约 43 字符 const key = `flnxi_${randomBytes(32).toString('base64url')}`; const hash = hashApiKey(key); return { key, hash }; } /** * 对 API Key 进行哈希 */ export function hashApiKey(key: string): string { return createHash('sha256').update(key).digest('hex'); } /** * 验证 API Key * 返回 API Key 记录(如果有效)或 null */ export async function verifyApiKey( key: string | null | undefined, prismaClient: ApiKeyPrismaClient ): Promise<{ valid: boolean; apiKey?: { id: string; name: string }; error?: string; }> { if (!key) { return { valid: false, error: 'API Key 未提供' }; } const hash = hashApiKey(key); try { const apiKey = await prismaClient.apiKey.findUnique({ where: { keyHash: hash }, }); if (!apiKey) { return { valid: false, error: 'API Key 无效' }; } if (!apiKey.isActive) { return { valid: false, error: 'API Key 已被禁用' }; } // 更新最后使用时间(异步,不阻塞) prismaClient.apiKey.update({ where: { id: apiKey.id }, data: { lastUsedAt: new Date() }, }).catch((err: Error) => { console.warn('[ApiKey] 更新最后使用时间失败:', err.message); }); return { valid: true, apiKey: { id: apiKey.id, name: apiKey.name }, }; } catch (error) { console.error('[ApiKey] 验证失败:', error); return { valid: false, error: '验证服务异常' }; } } /** * 创建新的 API Key(管理员用) */ export async function createApiKey( name: string, prismaClient: ApiKeyPrismaClient ): Promise<{ success: boolean; key?: string; error?: string; }> { try { const { key, hash } = generateApiKey(); await prismaClient.apiKey.create({ data: { name, keyHash: hash, }, }); // 返回原始 key,只显示这一次 return { success: true, key }; } catch (error) { console.error('[ApiKey] 创建失败:', error); return { success: false, error: '创建失败' }; } } /** * 禁用 API Key */ export async function disableApiKey( id: string, prismaClient: ApiKeyPrismaClient ): Promise { try { await prismaClient.apiKey.update({ where: { id }, data: { isActive: false }, }); return true; } catch (error) { console.error('[ApiKey] 禁用失败:', error); return false; } } /** * 列出所有 API Key(不含原始 key) */ export async function listApiKeys(prismaClient: ApiKeyPrismaClient) { return prismaClient.apiKey.findMany({ select: { id: true, name: true, isActive: true, lastUsedAt: true, createdAt: true, }, orderBy: { createdAt: 'desc' }, }); }