package api import ( "net/http" "time" "d:\项目\dobaochet\backend\config" "d:\项目\dobaochet\backend\db" "d:\项目\dobaochet\backend\models" "d:\项目\dobaochet\backend\utils" "github.com/gin-gonic/gin" ) // UserAPI 用户API结构体 type UserAPI struct { cfg *config.Config } // NewUserAPI 创建用户API实例 func NewUserAPI(cfg *config.Config) *UserAPI { return &UserAPI{cfg: cfg} } // Register 注册用户 func (api *UserAPI) Register(c *gin.Context) { var req models.RegisterRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 检查用户名是否已存在 var existingUser models.User if result := db.GetDB().Where("username = ?", req.Username).First(&existingUser); result.Error == nil { c.JSON(http.StatusConflict, gin.H{"error": "用户名已存在"}) return } // 检查邮箱是否已存在 if result := db.GetDB().Where("email = ?", req.Email).First(&existingUser); result.Error == nil { c.JSON(http.StatusConflict, gin.H{"error": "邮箱已存在"}) return } // 密码加密 hashedPassword, err := utils.HashPassword(req.Password) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "密码加密失败"}) return } // 创建用户 user := models.User{ Username: req.Username, Email: req.Email, Password: hashedPassword, IsActive: true, LastLoginAt: time.Now(), Quota: models.Quota{ TotalTokens: api.cfg.Quota.DefaultTotalTokens, UsedTokens: 0, ResetAt: time.Now().Add(api.cfg.Quota.ResetInterval), TokenLimit: api.cfg.Quota.DefaultTokenLimit, }, } if result := db.GetDB().Create(&user); result.Error != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "创建用户失败"}) return } // 返回用户信息(隐藏敏感信息) c.JSON(http.StatusCreated, gin.H{ "id": user.ID, "username": user.Username, "email": user.Email, "is_admin": user.IsAdmin, "is_active": user.IsActive, "created_at": user.CreatedAt, }) } // Login 用户登录 func (api *UserAPI) Login(c *gin.Context) { var req models.LoginRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 查找用户 var user models.User if result := db.GetDB().Preload("Quota").Where("username = ?", req.Username).First(&user); result.Error != nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"}) return } // 验证密码 if err := utils.VerifyPassword(user.Password, req.Password); err != nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"}) return } // 检查用户是否激活 if !user.IsActive { c.JSON(http.StatusForbidden, gin.H{"error": "用户已被禁用"}) return } // 更新登录时间 user.LastLoginAt = time.Now() db.GetDB().Save(&user) // 生成JWT令牌 token, err := utils.GenerateToken( user.ID, user.Username, user.IsAdmin, api.cfg.JWT.SecretKey, api.cfg.JWT.AccessTokenExpire, ) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "生成令牌失败"}) return } // 返回登录结果 c.JSON(http.StatusOK, models.LoginResponse{ Token: token, User: models.UserResponse{ ID: user.ID, Username: user.Username, Email: user.Email, IsAdmin: user.IsAdmin, IsActive: user.IsActive, CreatedAt: user.CreatedAt, Quota: user.Quota, }, }) } // GetUserInfo 获取当前用户信息 func (api *UserAPI) GetUserInfo(c *gin.Context) { // 从上下文获取用户信息 user, exists := c.Get("user") if !exists { c.JSON(http.StatusUnauthorized, gin.H{"error": "未认证"}) return } currentUser := user.(models.User) c.JSON(http.StatusOK, models.UserResponse{ ID: currentUser.ID, Username: currentUser.Username, Email: currentUser.Email, IsAdmin: currentUser.IsAdmin, IsActive: currentUser.IsActive, CreatedAt: currentUser.CreatedAt, Quota: currentUser.Quota, }) } // UpdateUserInfo 更新用户信息 func (api *UserAPI) UpdateUserInfo(c *gin.Context) { // 从上下文获取用户信息 user, exists := c.Get("user") if !exists { c.JSON(http.StatusUnauthorized, gin.H{"error": "未认证"}) return } currentUser := user.(models.User) // 解析请求 var req struct { Email string `json:"email" binding:"omitempty,email"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 更新用户信息 if req.Email != "" && req.Email != currentUser.Email { // 检查邮箱是否已被使用 var existingUser models.User if result := db.GetDB().Where("email = ? AND id != ?", req.Email, currentUser.ID).First(&existingUser); result.Error == nil { c.JSON(http.StatusConflict, gin.H{"error": "邮箱已被使用"}) return } currentUser.Email = req.Email } if result := db.GetDB().Save(¤tUser); result.Error != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "更新用户信息失败"}) return } c.JSON(http.StatusOK, models.UserResponse{ ID: currentUser.ID, Username: currentUser.Username, Email: currentUser.Email, IsAdmin: currentUser.IsAdmin, IsActive: currentUser.IsActive, CreatedAt: currentUser.CreatedAt, Quota: currentUser.Quota, }) } // ChangePassword 修改密码 func (api *UserAPI) ChangePassword(c *gin.Context) { // 从上下文获取用户信息 user, exists := c.Get("user") if !exists { c.JSON(http.StatusUnauthorized, gin.H{"error": "未认证"}) return } currentUser := user.(models.User) // 解析请求 var req struct { OldPassword string `json:"old_password" binding:"required"` NewPassword string `json:"new_password" binding:"required,min=6"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 验证旧密码 if err := utils.VerifyPassword(currentUser.Password, req.OldPassword); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "旧密码错误"}) return } // 加密新密码 newHashedPassword, err := utils.HashPassword(req.NewPassword) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "密码加密失败"}) return } // 更新密码 currentUser.Password = newHashedPassword if result := db.GetDB().Save(¤tUser); result.Error != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "修改密码失败"}) return } c.JSON(http.StatusOK, gin.H{"message": "密码修改成功"}) } // RegisterRoutes 注册用户路由 func (api *UserAPI) RegisterRoutes(router *gin.RouterGroup) { userGroup := router.Group("/users") { // 公开路由 userGroup.POST("/register", api.Register) userGroup.POST("/login", api.Login) // 需要认证的路由 authGroup := userGroup.Group("/") authGroup.Use(AuthMiddleware(api.cfg)) { authGroup.GET("/me", api.GetUserInfo) authGroup.PUT("/me", api.UpdateUserInfo) authGroup.PUT("/me/password", api.ChangePassword) } } }