369 lines
10 KiB
TypeScript
369 lines
10 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server'
|
|
import { getMongoClient } from '@/lib/mongodb'
|
|
|
|
// API密钥接口
|
|
interface APIKey {
|
|
id: string
|
|
name: string
|
|
key: string
|
|
secret: string
|
|
status: 'active' | 'disabled' | 'expired'
|
|
createdAt: string
|
|
expiresAt: string | null
|
|
lastUsed: string | null
|
|
permissions: FieldPermission[]
|
|
rateLimit: {
|
|
requestsPerDay: number
|
|
requestsPerMonth: number
|
|
}
|
|
billing: {
|
|
plan: 'free' | 'basic' | 'pro' | 'enterprise'
|
|
usedCredits: number
|
|
totalCredits: number
|
|
}
|
|
callStats: {
|
|
today: number
|
|
thisMonth: number
|
|
total: number
|
|
}
|
|
}
|
|
|
|
// 字段权限接口
|
|
interface FieldPermission {
|
|
fieldGroup: string
|
|
fields: {
|
|
name: string
|
|
label: string
|
|
enabled: boolean
|
|
price: number
|
|
}[]
|
|
}
|
|
|
|
// 计费套餐
|
|
const BILLING_PLANS = {
|
|
free: { credits: 1000, requestsPerDay: 100, requestsPerMonth: 3000 },
|
|
basic: { credits: 10000, requestsPerDay: 1000, requestsPerMonth: 30000 },
|
|
pro: { credits: 50000, requestsPerDay: 5000, requestsPerMonth: 150000 },
|
|
enterprise: { credits: -1, requestsPerDay: -1, requestsPerMonth: -1 },
|
|
}
|
|
|
|
// 默认字段权限
|
|
const DEFAULT_FIELD_PERMISSIONS: FieldPermission[] = [
|
|
{
|
|
fieldGroup: '基础信息',
|
|
fields: [
|
|
{ name: 'phone', label: '手机号', enabled: true, price: 1 },
|
|
{ name: 'qq', label: 'QQ号', enabled: true, price: 1 },
|
|
{ name: 'wechat', label: '微信号', enabled: false, price: 2 },
|
|
{ name: 'email', label: '邮箱', enabled: false, price: 1 },
|
|
{ name: 'nickname', label: '昵称', enabled: true, price: 0.5 },
|
|
]
|
|
},
|
|
{
|
|
fieldGroup: '用户画像',
|
|
fields: [
|
|
{ name: 'rfm_score', label: 'RFM评分', enabled: true, price: 2 },
|
|
{ name: 'user_level', label: '用户等级', enabled: true, price: 1 },
|
|
{ name: 'value_score', label: '价值评分', enabled: false, price: 3 },
|
|
{ name: 'activity_score', label: '活跃度评分', enabled: false, price: 2 },
|
|
{ name: 'loyalty_score', label: '忠诚度评分', enabled: false, price: 2 },
|
|
]
|
|
},
|
|
{
|
|
fieldGroup: '标签数据',
|
|
fields: [
|
|
{ name: 'basic_tags', label: '基础标签', enabled: true, price: 1 },
|
|
{ name: 'behavior_tags', label: '行为标签', enabled: false, price: 2 },
|
|
{ name: 'preference_tags', label: '偏好标签', enabled: false, price: 2 },
|
|
{ name: 'ai_tags', label: 'AI智能标签', enabled: false, price: 5 },
|
|
{ name: 'custom_tags', label: '自定义标签', enabled: true, price: 1 },
|
|
]
|
|
},
|
|
{
|
|
fieldGroup: '行为数据',
|
|
fields: [
|
|
{ name: 'last_active', label: '最后活跃时间', enabled: true, price: 0.5 },
|
|
{ name: 'visit_count', label: '访问次数', enabled: false, price: 1 },
|
|
{ name: 'purchase_history', label: '购买历史', enabled: false, price: 5 },
|
|
{ name: 'interaction_log', label: '交互记录', enabled: false, price: 3 },
|
|
{ name: 'channel_source', label: '渠道来源', enabled: true, price: 1 },
|
|
]
|
|
},
|
|
{
|
|
fieldGroup: '扩展数据',
|
|
fields: [
|
|
{ name: 'social_bindings', label: '社交绑定', enabled: false, price: 3 },
|
|
{ name: 'device_info', label: '设备信息', enabled: false, price: 2 },
|
|
{ name: 'location_data', label: '位置数据', enabled: false, price: 4 },
|
|
{ name: 'risk_assessment', label: '风险评估', enabled: false, price: 5 },
|
|
{ name: 'ai_insights', label: 'AI洞察', enabled: false, price: 10 },
|
|
]
|
|
},
|
|
]
|
|
|
|
const COLLECTION = 'api_keys'
|
|
const DB_NAME = 'KR'
|
|
|
|
async function getCollection() {
|
|
const client = await getMongoClient()
|
|
return client.db(DB_NAME).collection<APIKey & { _id?: any }>(COLLECTION)
|
|
}
|
|
|
|
// 生成随机密钥
|
|
function generateKey(prefix: string): string {
|
|
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789'
|
|
let result = prefix
|
|
for (let i = 0; i < 20; i++) {
|
|
result += chars.charAt(Math.floor(Math.random() * chars.length))
|
|
}
|
|
return result
|
|
}
|
|
|
|
// GET: 获取API密钥列表
|
|
export async function GET(request: NextRequest) {
|
|
try {
|
|
const { searchParams } = new URL(request.url)
|
|
const action = searchParams.get('action')
|
|
const keyId = searchParams.get('id')
|
|
|
|
const col = await getCollection()
|
|
|
|
// 验证单个密钥
|
|
if (action === 'validate') {
|
|
const apiKey = searchParams.get('key')
|
|
const apiSecret = searchParams.get('secret')
|
|
|
|
const key = await col.findOne({ key: apiKey, secret: apiSecret })
|
|
|
|
if (!key) {
|
|
return NextResponse.json({
|
|
success: false,
|
|
error: '无效的API密钥'
|
|
}, { status: 401 })
|
|
}
|
|
|
|
if (key.status !== 'active') {
|
|
return NextResponse.json({
|
|
success: false,
|
|
error: `密钥状态: ${key.status}`
|
|
}, { status: 403 })
|
|
}
|
|
|
|
if (key.expiresAt && new Date(key.expiresAt) < new Date()) {
|
|
return NextResponse.json({
|
|
success: false,
|
|
error: '密钥已过期'
|
|
}, { status: 403 })
|
|
}
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
data: {
|
|
id: key.id,
|
|
name: key.name,
|
|
plan: key.billing.plan,
|
|
permissions: key.permissions,
|
|
rateLimit: key.rateLimit,
|
|
creditsRemaining: key.billing.totalCredits === -1 ? -1 : key.billing.totalCredits - key.billing.usedCredits
|
|
}
|
|
})
|
|
}
|
|
|
|
// 获取单个密钥详情
|
|
if (keyId) {
|
|
const key = await col.findOne({ id: keyId })
|
|
if (!key) {
|
|
return NextResponse.json({
|
|
success: false,
|
|
error: '密钥不存在'
|
|
}, { status: 404 })
|
|
}
|
|
return NextResponse.json({
|
|
success: true,
|
|
data: key
|
|
})
|
|
}
|
|
|
|
// 获取所有密钥列表
|
|
const keys = await col.find({}).sort({ createdAt: -1 }).toArray()
|
|
return NextResponse.json({
|
|
success: true,
|
|
data: keys.map(k => ({
|
|
...k,
|
|
key: k.key.substring(0, 12) + '••••••••••••',
|
|
secret: '••••••••••••••••'
|
|
})),
|
|
total: keys.length
|
|
})
|
|
|
|
} catch (error) {
|
|
console.error('获取API密钥失败:', error)
|
|
return NextResponse.json({
|
|
success: false,
|
|
error: '获取API密钥失败'
|
|
}, { status: 500 })
|
|
}
|
|
}
|
|
|
|
// POST: 创建新API密钥
|
|
export async function POST(request: NextRequest) {
|
|
try {
|
|
const body = await request.json()
|
|
const { name, plan = 'basic', expiresAt } = body
|
|
|
|
if (!name) {
|
|
return NextResponse.json({
|
|
success: false,
|
|
error: '请提供密钥名称'
|
|
}, { status: 400 })
|
|
}
|
|
|
|
const planConfig = BILLING_PLANS[plan as keyof typeof BILLING_PLANS] || BILLING_PLANS.basic
|
|
|
|
const newKey: APIKey = {
|
|
id: `key_${Date.now()}`,
|
|
name,
|
|
key: generateKey('sk-archer-'),
|
|
secret: generateKey('sec-'),
|
|
status: 'active',
|
|
createdAt: new Date().toISOString().split('T')[0],
|
|
expiresAt: expiresAt || null,
|
|
lastUsed: null,
|
|
permissions: JSON.parse(JSON.stringify(DEFAULT_FIELD_PERMISSIONS)),
|
|
rateLimit: {
|
|
requestsPerDay: planConfig.requestsPerDay,
|
|
requestsPerMonth: planConfig.requestsPerMonth
|
|
},
|
|
billing: {
|
|
plan: plan as 'free' | 'basic' | 'pro' | 'enterprise',
|
|
usedCredits: 0,
|
|
totalCredits: planConfig.credits
|
|
},
|
|
callStats: { today: 0, thisMonth: 0, total: 0 }
|
|
}
|
|
|
|
const col = await getCollection()
|
|
await col.insertOne(newKey)
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
data: newKey,
|
|
message: '密钥创建成功'
|
|
})
|
|
|
|
} catch (error) {
|
|
console.error('创建API密钥失败:', error)
|
|
return NextResponse.json({
|
|
success: false,
|
|
error: '创建API密钥失败'
|
|
}, { status: 500 })
|
|
}
|
|
}
|
|
|
|
// PUT: 更新API密钥
|
|
export async function PUT(request: NextRequest) {
|
|
try {
|
|
const body = await request.json()
|
|
const { id, action, permissions, status } = body
|
|
|
|
const col = await getCollection()
|
|
const key = await col.findOne({ id })
|
|
|
|
if (!key) {
|
|
return NextResponse.json({
|
|
success: false,
|
|
error: '密钥不存在'
|
|
}, { status: 404 })
|
|
}
|
|
|
|
if (action === 'updatePermissions' && permissions) {
|
|
await col.updateOne({ id }, { $set: { permissions } })
|
|
const updated = await col.findOne({ id })
|
|
return NextResponse.json({
|
|
success: true,
|
|
data: updated,
|
|
message: '权限更新成功'
|
|
})
|
|
}
|
|
|
|
if (action === 'toggleStatus') {
|
|
const newStatus = key.status === 'active' ? 'disabled' : 'active'
|
|
await col.updateOne({ id }, { $set: { status: newStatus } })
|
|
const updated = await col.findOne({ id })
|
|
return NextResponse.json({
|
|
success: true,
|
|
data: updated,
|
|
message: `密钥已${newStatus === 'active' ? '启用' : '禁用'}`
|
|
})
|
|
}
|
|
|
|
if (action === 'regenerate') {
|
|
const newKey = generateKey('sk-archer-')
|
|
const newSecret = generateKey('sec-')
|
|
await col.updateOne({ id }, { $set: { key: newKey, secret: newSecret } })
|
|
const updated = await col.findOne({ id })
|
|
return NextResponse.json({
|
|
success: true,
|
|
data: updated,
|
|
message: '密钥已重新生成'
|
|
})
|
|
}
|
|
|
|
if (status) {
|
|
await col.updateOne({ id }, { $set: { status } })
|
|
}
|
|
|
|
const updated = await col.findOne({ id })
|
|
return NextResponse.json({
|
|
success: true,
|
|
data: updated,
|
|
message: '更新成功'
|
|
})
|
|
|
|
} catch (error) {
|
|
console.error('更新API密钥失败:', error)
|
|
return NextResponse.json({
|
|
success: false,
|
|
error: '更新API密钥失败'
|
|
}, { status: 500 })
|
|
}
|
|
}
|
|
|
|
// DELETE: 删除API密钥
|
|
export async function DELETE(request: NextRequest) {
|
|
try {
|
|
const { searchParams } = new URL(request.url)
|
|
const id = searchParams.get('id')
|
|
|
|
if (!id) {
|
|
return NextResponse.json({
|
|
success: false,
|
|
error: '请提供密钥ID'
|
|
}, { status: 400 })
|
|
}
|
|
|
|
const col = await getCollection()
|
|
const result = await col.findOneAndDelete({ id })
|
|
|
|
if (!result) {
|
|
return NextResponse.json({
|
|
success: false,
|
|
error: '密钥不存在'
|
|
}, { status: 404 })
|
|
}
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
data: { id: result.id, name: result.name },
|
|
message: '密钥已删除'
|
|
})
|
|
|
|
} catch (error) {
|
|
console.error('删除API密钥失败:', error)
|
|
return NextResponse.json({
|
|
success: false,
|
|
error: '删除API密钥失败'
|
|
}, { status: 500 })
|
|
}
|
|
}
|