From c242694d9b5707c4be0c7dd056cdff7471e48802 Mon Sep 17 00:00:00 2001 From: clz Date: Sun, 11 Jan 2026 19:11:47 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=92=8C=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 上传文件名添加唯一ID避免覆盖 - 支持通过环境变量配置 JWT 密钥和 Token 过期时间 - 支持通过环境变量覆盖管理员账号(可选) --- docker-compose.yaml | 9 +++++++- server/config/config.go | 45 ++++++++++++++++++++++++++++++++++++++++ server/handler/upload.go | 23 ++++++++++++++++++-- 3 files changed, 74 insertions(+), 3 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index ec5dccc..73503ad 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -38,8 +38,15 @@ services: ANALYZER_MODE: "http" MONGO_URI: "mongodb://admin:password@mongodb:27017" MONGO_DATABASE: "billai" + # 认证配置 + JWT_SECRET: "billai-secret-key-2026" + TOKEN_EXPIRY: "1" # Token 过期时间(小时) + # 管理员账号(如需覆盖配置文件中的用户,取消注释以下配置) + ADMIN_USERNAME: "admin" + ADMIN_PASSWORD: "admin123" + ADMIN_NAME: "管理员" volumes: - - ./server/uploads:/app/uploads + - ./uploads:/app/uploads - ./server/outputs:/app/outputs depends_on: analyzer: diff --git a/server/config/config.go b/server/config/config.go index 678883d..ab13ebc 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "path/filepath" + "strconv" "gopkg.in/yaml.v3" ) @@ -260,6 +261,50 @@ func Load() { if cleanedColl := os.Getenv("MONGO_CLEANED_COLLECTION"); cleanedColl != "" { Global.MongoCleanedCollection = cleanedColl } + // 认证相关环境变量覆盖 + if jwtSecret := os.Getenv("JWT_SECRET"); jwtSecret != "" { + Global.JWTSecret = jwtSecret + } + if tokenExpiry := os.Getenv("TOKEN_EXPIRY"); tokenExpiry != "" { + if expiry, err := strconv.Atoi(tokenExpiry); err == nil && expiry > 0 { + Global.TokenExpiry = expiry + } + } + // 管理员账号环境变量覆盖(覆盖配置文件中的第一个用户) + adminUser := os.Getenv("ADMIN_USERNAME") + adminPass := os.Getenv("ADMIN_PASSWORD") + if adminUser != "" && adminPass != "" { + adminName := os.Getenv("ADMIN_NAME") + if adminName == "" { + adminName = "管理员" + } + adminEmail := os.Getenv("ADMIN_EMAIL") + if adminEmail == "" { + adminEmail = adminUser + "@billai.com" + } + // 查找并更新 admin 用户,或添加新用户 + found := false + for i := range Global.Users { + if Global.Users[i].Username == adminUser || Global.Users[i].Role == "admin" { + Global.Users[i].Username = adminUser + Global.Users[i].Password = adminPass + Global.Users[i].Name = adminName + Global.Users[i].Email = adminEmail + Global.Users[i].Role = "admin" + found = true + break + } + } + if !found { + Global.Users = append(Global.Users, UserInfo{ + Username: adminUser, + Password: adminPass, + Name: adminName, + Email: adminEmail, + Role: "admin", + }) + } + } } // ResolvePath 解析路径(相对路径转为绝对路径) diff --git a/server/handler/upload.go b/server/handler/upload.go index b7ad193..be04a45 100644 --- a/server/handler/upload.go +++ b/server/handler/upload.go @@ -1,6 +1,8 @@ package handler import ( + "crypto/rand" + "encoding/hex" "fmt" "io" "net/http" @@ -52,9 +54,16 @@ func Upload(c *gin.Context) { } billType := req.Type - // 3. 保存上传的文件 + // 3. 保存上传的文件(添加唯一ID避免覆盖) timestamp := time.Now().Format("20060102_150405") - inputFileName := fmt.Sprintf("%s_%s", timestamp, header.Filename) + uniqueID := generateShortID() + + // 获取文件扩展名和基础名 + ext := filepath.Ext(header.Filename) + baseName := header.Filename[:len(header.Filename)-len(ext)] + + // 文件名格式: 时间戳_唯一ID_原始文件名 + inputFileName := fmt.Sprintf("%s_%s_%s%s", timestamp, uniqueID, baseName, ext) uploadDirAbs := config.ResolvePath(config.Global.UploadDir) inputPath := filepath.Join(uploadDirAbs, inputFileName) @@ -182,3 +191,13 @@ func generateFileSequence(dir, timestamp, billType, ext string) string { } return fmt.Sprintf("%03d", len(matches)+1) } + +// generateShortID 生成 6 位随机唯一标识符 +func generateShortID() string { + bytes := make([]byte, 3) // 3 字节 = 6 个十六进制字符 + if _, err := rand.Read(bytes); err != nil { + // 如果随机数生成失败,使用时间纳秒作为备选 + return fmt.Sprintf("%06x", time.Now().UnixNano()%0xFFFFFF) + } + return hex.EncodeToString(bytes) +}