From cdeb4ea9fbd8a8463b92ca19ebb3a5e36eeffbcd Mon Sep 17 00:00:00 2001
From: nanako <469449812@qq.com>
Date: Tue, 11 Nov 2025 16:05:58 +0800
Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9EAPI=E7=AE=A1=E7=90=86?=
=?UTF-8?q?=E9=A1=B5=E9=9D=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
backend/api/handlers.go | 117 +++++++++
backend/main.go | 5 +
frontend/src/App.jsx | 5 +
frontend/src/features/api-keys/api/index.js | 30 +++
.../api-keys/components/ApiKeyForm.jsx | 128 ++++++++++
.../api-keys/components/ApiKeyList.jsx | 231 ++++++++++++++++++
frontend/src/features/api-keys/index.jsx | 14 ++
7 files changed, 530 insertions(+)
create mode 100644 frontend/src/features/api-keys/api/index.js
create mode 100644 frontend/src/features/api-keys/components/ApiKeyForm.jsx
create mode 100644 frontend/src/features/api-keys/components/ApiKeyList.jsx
create mode 100644 frontend/src/features/api-keys/index.jsx
diff --git a/backend/api/handlers.go b/backend/api/handlers.go
index 9261ee8..13eb07f 100644
--- a/backend/api/handlers.go
+++ b/backend/api/handlers.go
@@ -555,3 +555,120 @@ func (h *APIHandler) ForceLogCleanupHandler(c *gin.Context) {
"success": report.Success,
})
}
+
+
+// ============ API Key 管理相关处理器 ============
+
+// APIKeyListResponse API Key列表响应
+type APIKeyListResponse struct {
+ ID uint `json:"id"`
+ Key string `json:"key"`
+ CreatedAt time.Time `json:"created_at"`
+}
+
+// GetAPIKeysHandler 获取所有API Key列表
+func (h *APIHandler) GetAPIKeysHandler(c *gin.Context) {
+ var apiKeys []models.APIKey
+
+ // 查询所有API Key
+ if err := h.DB.Order("created_at DESC").Find(&apiKeys).Error; err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch API keys"})
+ return
+ }
+
+ // 转换为响应格式
+ response := make([]APIKeyListResponse, len(apiKeys))
+ for i, key := range apiKeys {
+ response[i] = APIKeyListResponse{
+ ID: key.ID,
+ Key: key.Key,
+ CreatedAt: key.CreatedAt,
+ }
+ }
+
+ c.JSON(http.StatusOK, gin.H{
+ "api_keys": response,
+ "total": len(response),
+ })
+}
+
+// CreateAPIKeyRequest 创建API Key的请求结构
+type CreateAPIKeyRequest struct {
+ Key string `json:"key" binding:"required"`
+}
+
+// CreateAPIKeyHandler 创建新的API Key
+func (h *APIHandler) CreateAPIKeyHandler(c *gin.Context) {
+ var req CreateAPIKeyRequest
+
+ // 解析请求
+ if err := c.ShouldBindJSON(&req); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request format: " + err.Error()})
+ return
+ }
+
+ // 验证Key不为空
+ if req.Key == "" {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "API key cannot be empty"})
+ return
+ }
+
+ // 检查Key是否已存在
+ var existingKey models.APIKey
+ if err := h.DB.Where("key = ?", req.Key).First(&existingKey).Error; err == nil {
+ c.JSON(http.StatusConflict, gin.H{"error": "API key already exists"})
+ return
+ }
+
+ // 创建新的API Key
+ newAPIKey := models.APIKey{
+ Key: req.Key,
+ }
+
+ if err := h.DB.Create(&newAPIKey).Error; err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create API key"})
+ return
+ }
+
+ // 返回创建的API Key
+ c.JSON(http.StatusCreated, gin.H{
+ "message": "API key created successfully",
+ "api_key": APIKeyListResponse{
+ ID: newAPIKey.ID,
+ Key: newAPIKey.Key,
+ CreatedAt: newAPIKey.CreatedAt,
+ },
+ })
+}
+
+// DeleteAPIKeyHandler 删除指定的API Key
+func (h *APIHandler) DeleteAPIKeyHandler(c *gin.Context) {
+ // 获取API Key ID
+ keyID := c.Param("id")
+ if keyID == "" {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "API key ID is required"})
+ return
+ }
+
+ // 查找API Key
+ var apiKey models.APIKey
+ if err := h.DB.First(&apiKey, keyID).Error; err != nil {
+ if err == gorm.ErrRecordNotFound {
+ c.JSON(http.StatusNotFound, gin.H{"error": "API key not found"})
+ return
+ }
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to find API key"})
+ return
+ }
+
+ // 删除API Key
+ if err := h.DB.Delete(&apiKey).Error; err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete API key"})
+ return
+ }
+
+ c.JSON(http.StatusOK, gin.H{
+ "message": "API key deleted successfully",
+ "id": apiKey.ID,
+ })
+}
diff --git a/backend/main.go b/backend/main.go
index 4110999..a68ce2d 100644
--- a/backend/main.go
+++ b/backend/main.go
@@ -118,6 +118,11 @@ func main() {
// Log Cleaner Management
api_.GET("/log-cleaner/status", handler.GetLogCleanerStatusHandler)
api_.POST("/log-cleaner/force-cleanup", handler.ForceLogCleanupHandler)
+
+ // API Keys Management
+ api_.GET("/api-keys", handler.GetAPIKeysHandler)
+ api_.POST("/api-keys", handler.CreateAPIKeyHandler)
+ api_.DELETE("/api-keys/:id", handler.DeleteAPIKeyHandler)
}
// 设置优雅关闭信号处理
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index cb3a957..e65c632 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -3,6 +3,7 @@ import PageLayout from './components/layout/PageLayout';
import ProvidersPage from './features/providers';
import VirtualModelsPage from './features/virtual-models';
import LogsPage from './features/logs';
+import ApiKeysPage from './features/api-keys';
import './App.css';
function App() {
@@ -18,6 +19,10 @@ function App() {
{
label: '请求日志',
content:
+ 管理用于访问AI Gateway的API密钥 +
+| + ID + | ++ API Key + | ++ 创建时间 + | ++ 操作 + | +
|---|---|---|---|
|
+
+
+
+ 暂无API Key +点击"创建API Key"按钮添加新的密钥 + |
+ |||
|
+
+ #{apiKey.id || 'N/A'}
+
+ |
+
+
+
+
+ {apiKey.key || 'N/A'}
+
+
+ |
+
+
+ {formatDate(apiKey.created_at)}
+
+ |
+ + + | +
Authorization: Bearer YOUR_API_KEY