package auth import ( "net/http" "strings" "mrcc/pkg/response" "github.com/gin-gonic/gin" ) type Handler struct { store *UserStore jwt *JWTManager } func NewHandler(store *UserStore, jwtMgr *JWTManager) *Handler { return &Handler{store: store, jwt: jwtMgr} } // RegisterAuthRoutes 注册认证路由 (/api/auth) func (h *Handler) RegisterAuthRoutes(r *gin.RouterGroup) { r.POST("/register", h.Register) r.POST("/login", h.Login) r.GET("/me", h.AuthMiddleware(), h.Me) } // RegisterEconomyRoutes 注册经济路由 (/api) func (h *Handler) RegisterEconomyRoutes(r *gin.RouterGroup) { r.POST("/daily-reward", h.AuthMiddleware(), h.DailyReward) r.POST("/spend", h.AuthMiddleware(), h.Spend) r.POST("/buy", h.AuthMiddleware(), h.Buy) r.POST("/use-item", h.AuthMiddleware(), h.UseItem) } // RegisterRoutes 注册全部路由(兼容旧调用) func (h *Handler) RegisterRoutes(r *gin.RouterGroup) { h.RegisterAuthRoutes(r) h.RegisterEconomyRoutes(r) } type registerReq struct { Username string `json:"username" binding:"required,min=3,max=20"` Password string `json:"password" binding:"required,min=6,max=50"` } // Register 用户注册 func (h *Handler) Register(c *gin.Context) { var req registerReq if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, http.StatusBadRequest, "参数无效: "+err.Error()) return } user, err := h.store.Create(req.Username, req.Password) if err != nil { response.Error(c, http.StatusConflict, err.Error()) return } token, err := h.jwt.Generate(user) if err != nil { response.Error(c, http.StatusInternalServerError, "生成令牌失败") return } response.OK(c, gin.H{ "token": token, "user": userToMap(user), }) } // Login 用户登录 func (h *Handler) Login(c *gin.Context) { var req registerReq if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, http.StatusBadRequest, "参数无效: "+err.Error()) return } user, err := h.store.VerifyPassword(req.Username, req.Password) if err != nil { response.Error(c, http.StatusUnauthorized, err.Error()) return } token, err := h.jwt.Generate(user) if err != nil { response.Error(c, http.StatusInternalServerError, "生成令牌失败") return } response.OK(c, gin.H{ "token": token, "user": userToMap(user), }) } // Me 获取当前用户完整信息 func (h *Handler) Me(c *gin.Context) { claims, exists := c.Get("claims") if !exists { response.Error(c, http.StatusUnauthorized, "未认证") return } cl := claims.(*Claims) user, ok := h.store.GetByID(cl.UserID) if !ok { response.Error(c, http.StatusNotFound, "用户不存在") return } response.OK(c, userToMap(user)) } // DailyReward 每日登录奖励 func (h *Handler) DailyReward(c *gin.Context) { claims, exists := c.Get("claims") if !exists { response.Error(c, http.StatusUnauthorized, "未认证") return } cl := claims.(*Claims) result, err := h.store.DailyLogin(cl.UserID) if err != nil { response.Error(c, http.StatusInternalServerError, err.Error()) return } response.OK(c, result) } type spendReq struct { Currency string `json:"currency" binding:"required"` Amount int64 `json:"amount" binding:"required,min=1"` } // Spend 消费货币 func (h *Handler) Spend(c *gin.Context) { claims, exists := c.Get("claims") if !exists { response.Error(c, http.StatusUnauthorized, "未认证") return } cl := claims.(*Claims) var req spendReq if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, http.StatusBadRequest, "参数无效: "+err.Error()) return } if err := h.store.SpendCurrency(cl.UserID, req.Currency, req.Amount); err != nil { response.Error(c, http.StatusBadRequest, err.Error()) return } // 返回最新余额 user, _ := h.store.GetByID(cl.UserID) response.OK(c, gin.H{ "message": "消费成功", "currency": req.Currency, "amount": req.Amount, "user": userToMap(user), }) } type buyReq struct { ItemID string `json:"item_id" binding:"required"` ItemName string `json:"item_name" binding:"required"` Currency string `json:"currency" binding:"required"` Amount int64 `json:"amount" binding:"required,min=1"` Quantity int `json:"quantity"` } // Buy 购买商品 (含库存追踪) func (h *Handler) Buy(c *gin.Context) { claims, _ := c.Get("claims"); cl := claims.(*Claims) var req buyReq if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, http.StatusBadRequest, err.Error()); return } if req.Quantity <= 0 { req.Quantity = 1 } result, err := h.store.BuyItem(cl.UserID, req.ItemID, req.ItemName, req.Currency, req.Amount, req.Quantity) if err != nil { response.Error(c, http.StatusBadRequest, err.Error()); return } response.OK(c, result) } type useReq struct { ItemID string `json:"item_id" binding:"required"` } // UseItem 使用道具 func (h *Handler) UseItem(c *gin.Context) { claims, _ := c.Get("claims"); cl := claims.(*Claims) var req useReq if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, http.StatusBadRequest, err.Error()); return } result, err := h.store.UseItem(cl.UserID, req.ItemID) if err != nil { response.Error(c, http.StatusBadRequest, err.Error()); return } response.OK(c, result) } // AuthMiddleware JWT 认证中间件 func (h *Handler) AuthMiddleware() gin.HandlerFunc { return func(c *gin.Context) { auth := c.GetHeader("Authorization") if auth == "" { response.Error(c, http.StatusUnauthorized, "缺少认证令牌") c.Abort() return } parts := strings.SplitN(auth, " ", 2) if len(parts) != 2 || parts[0] != "Bearer" { response.Error(c, http.StatusUnauthorized, "认证格式错误") c.Abort() return } claims, err := h.jwt.Verify(parts[1]) if err != nil { response.Error(c, http.StatusUnauthorized, "令牌无效或已过期") c.Abort() return } c.Set("claims", claims) c.Next() } }