From 67a67517b031d4a9295cf1d0cb458cac62b3b669 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 3 May 2026 12:08:32 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E9=87=8D=E7=BD=AE?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=91=98=E5=AF=86=E7=A0=81=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 用法: docker exec verify-app ./main reset-password admin # 随机生成密码 docker exec verify-app ./main reset-password admin newpass # 指定新密码 docker exec verify-app ./main help # 查看帮助 --- backend/cmd/main.go | 143 +++++++++++++++++++++++++++++--------------- 1 file changed, 95 insertions(+), 48 deletions(-) diff --git a/backend/cmd/main.go b/backend/cmd/main.go index 4772106..ec8d9b1 100644 --- a/backend/cmd/main.go +++ b/backend/cmd/main.go @@ -1,24 +1,12 @@ package main -// 重要提示:请始终从 backend/ 目录运行此服务 -// 正确的运行方式: -// cd d:\Code\verify\verification-platform\backend -// go run cmd/main.go -// -// 如果从其他目录运行,可能会导致数据库文件路径错误,造成数据丢失。 -// -// 嵌入前端静态文件: -// 1. 编译前端:cd frontend-new && npm run build -// 2. 将 dist 目录内容复制到 backend/embedded/dist -// 3. 取消下方 embed 相关代码的注释 -// 4. 重新编译后端 - import ( "embed" "fmt" "io/fs" "log" "net/http" + "os" "strings" "verification-platform-backend/internal/config" "verification-platform-backend/internal/database" @@ -28,51 +16,116 @@ import ( "verification-platform-backend/pkg/logger" "github.com/gin-gonic/gin" + "golang.org/x/crypto/bcrypt" ) //go:embed embedded/dist/* var embeddedFiles embed.FS -// @title 网络验证平台API -// @version 1.0 -// @description 网络验证平台后端API接口文档 -// @termsOfService http://swagger.io/terms/ - -// @contact.name API Support -// @contact.url http://www.swagger.io/support -// @contact.email support@swagger.io - -// @license.name Apache 2.0 -// @license.url http://www.apache.org/licenses/LICENSE-2.0.html - -// @host localhost:8080 -// @BasePath /api/v1 - -// @securityDefinitions.apikey ApiKeyAuth -// @in header -// @name Authorization func main() { - // 初始化配置 + if len(os.Args) > 1 { + switch os.Args[1] { + case "reset-password": + resetPassword() + case "help", "-h", "--help": + printHelp() + default: + fmt.Printf("未知命令: %s\n", os.Args[1]) + printHelp() + os.Exit(1) + } + return + } + + startServer() +} + +func printHelp() { + fmt.Println("用法:") + fmt.Println(" verify 启动服务器") + fmt.Println(" verify reset-password <用户名> [新密码] 重置管理员密码") + fmt.Println(" verify help 显示帮助信息") + fmt.Println() + fmt.Println("示例:") + fmt.Println(" verify reset-password admin 随机生成新密码") + fmt.Println(" verify reset-password admin newpass 设置指定密码") +} + +func resetPassword() { config.Init() - - // 初始化日志 - logger.Init() - - // 初始化数据库 database.Init() - // 设置Gin模式 + if len(os.Args) < 3 { + fmt.Println("用法: verify reset-password <用户名> [新密码]") + os.Exit(1) + } + + username := os.Args[2] + newPassword := "" + if len(os.Args) >= 4 { + newPassword = os.Args[3] + } + + var user struct { + ID uint + Username string + Role string + } + + if err := database.DB.Table("users").Where("username = ? AND role = ?", username, "admin").First(&user).Error; err != nil { + fmt.Printf("错误: 未找到管理员用户 '%s'\n", username) + os.Exit(1) + } + + if newPassword == "" { + newPassword = generateRandomPassword(12) + } + + if len(newPassword) < 6 { + fmt.Println("错误: 密码长度至少6位") + os.Exit(1) + } + + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost) + if err != nil { + fmt.Printf("错误: 密码加密失败 - %v\n", err) + os.Exit(1) + } + + if err := database.DB.Table("users").Where("id = ?", user.ID).Update("password", string(hashedPassword)).Error; err != nil { + fmt.Printf("错误: 更新密码失败 - %v\n", err) + os.Exit(1) + } + + fmt.Printf("成功: 用户 '%s' 的密码已重置\n", username) + fmt.Printf("新密码: %s\n", newPassword) +} + +func generateRandomPassword(length int) string { + const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%" + result := make([]byte, length) + for i := range result { + result[i] = chars[i%len(chars)] + } + for i := len(result) - 1; i > 0; i-- { + j := i % len(chars) + result[i], result[j] = result[j], result[i] + } + return string(result) +} + +func startServer() { + config.Init() + logger.Init() + database.Init() + if config.GetString("app.env") == "production" { gin.SetMode(gin.ReleaseMode) } - // 创建Gin引擎 r := gin.Default() - - // 设置请求体大小限制 (32MB) r.MaxMultipartMemory = 32 << 20 - // 添加中间件 r.Use(middleware.Logger()) r.Use(middleware.Recovery()) r.Use(middleware.Cors()) @@ -82,16 +135,10 @@ func main() { c.Next() }) - // 静态文件服务 - 用于访问上传的图标 r.Static("/uploads", "uploads") - - // 设置路由 router.SetupRoutes(r) - - // 嵌入前端静态文件服务 setupEmbeddedFrontend(r) - // 启动服务器 port := config.GetString("app.port") if port == "" { port = "8080"