package auth import ( "cls/internal/application/auth" "cls/internal/interfaces" "cls/pkg/jwtfx" "cls/pkg/logger" "fmt" jwt "github.com/appleboy/gin-jwt/v2" "github.com/gin-gonic/gin" "net/http" auth_middleware "cls/internal/infrastructure/middleware/auth" ) type AuthHandler struct { captchaService *auth.CaptchaService service *auth.AuthService log logger.Logger } var _ interfaces.Handler = (*AuthHandler)(nil) func NewAuthHandler(captcha *auth.CaptchaService, service *auth.AuthService, log logger.New) *AuthHandler { return &AuthHandler{captcha, service, log("cls:interfaces:auth")} } // getUserIdentifier 从 JWT token 中获取用户标识 func (h *AuthHandler) getUserIdentifier(c *gin.Context) string { claims := jwt.ExtractClaims(c) if claims["phone"] != nil { return claims["phone"].(string) } if claims["guest_id"] != nil { return claims["guest_id"].(string) } return "" } // isGuest 判断当前用户是否为游客 func (h *AuthHandler) isGuest(c *gin.Context) bool { claims := jwt.ExtractClaims(c) return claims["guest_id"] != nil } // GetSmsCaptcha 获取短信验证码 func (h *AuthHandler) GetSmsCaptcha(c *gin.Context) { var req struct { Phone string `json:"phone" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "无效的请求参数"}) return } // 从 JWT token 中获取用户标识 username := jwtfx.GetUserIdentifier(c) if username == "" { c.JSON(http.StatusUnauthorized, gin.H{"error": "未获取到用户标识"}) return } // 生成短信验证码 captcha, err := h.captchaService.GenerateSmsCaptcha(username, req.Phone) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{ "message": "验证码已发送", "resetAfter": captcha.ResetAfter, }) } // GetImageCaptcha 获取图片验证码 func (h *AuthHandler) GetImageCaptcha(c *gin.Context) { var req struct { Phone string `json:"phone"` } if err := c.ShouldBindQuery(&req); err != nil { fmt.Println(err.Error()) c.JSON(http.StatusBadRequest, gin.H{"error": "参数不完整"}) return } fmt.Println("获取图片验证码") // 生成验证码 captcha, err := h.captchaService.GenerateSlideVerify(req.Phone) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, captcha) } // VerifySmsCaptcha 验证短信验证码 func (h *AuthHandler) VerifySmsCaptcha(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"message": "验证成功"}) } func (h *AuthHandler) VerifyImageCaptcha(c *gin.Context) { var req struct { Token string `json:"token" binding:"required"` X int `json:"x" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "参数不完整"}) return } // 1. 先验证图片验证码 if b, err := h.captchaService.VerifySlide(req.Token, req.X); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "图片验证码错误"}) return } else { c.JSON(http.StatusOK, b) } } func (h *AuthHandler) LoginCaptcha(c *gin.Context) { var req struct { Phone string `json:"phone" binding:"required"` SmsCode string `json:"smsCode" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "参数不完整"}) return } // 从 JWT token 中获取用户标识 username := jwtfx.GetUserIdentifier(c) if username == "" { c.JSON(http.StatusUnauthorized, gin.H{"error": "未获取到用户标识"}) return } // 验证验证码 err := h.captchaService.VerifySmsCaptcha(username, req.Phone, req.SmsCode) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } token, err := h.service.LoginByCaptcha(req.Phone) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } else { c.JSON(http.StatusOK, token) } } func (h *AuthHandler) LoginPassword(c *gin.Context) { var req struct { Phone string `json:"phone" binding:"required"` CaptchaCode string `json:"captcha_code" binding:"required"` Password string `json:"password" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "参数不完整"}) return } // 从 JWT token 中获取用户标识 username := jwtfx.GetUserIdentifier(c) if username == "" { c.JSON(http.StatusUnauthorized, gin.H{"error": "未获取到用户标识"}) return } token, err := h.service.LoginByPassword(req.Phone, req.Password) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } else { c.JSON(http.StatusOK, token) } } func (h *AuthHandler) RegisterRouters(app gin.IRouter) { auth := app.Group("/auth") { auth.POST("/login-captcha", h.LoginCaptcha) auth.POST("/login-password", h.LoginPassword) auth.POST("/image-captcha", h.GetImageCaptcha) auth.POST("/sms-captcha", h.GetSmsCaptcha) auth.POST("/verify-image", h.VerifyImageCaptcha) auth.POST("/verify-sms", h.VerifySmsCaptcha) auth.POST("/decode-token", h.DecodeToken) } } // DecodeToken 解析 token 并返回原始的加密手机号 func (h *AuthHandler) DecodeToken(c *gin.Context) { var req struct { Token string `json:"token" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "参数不完整"}) return } // 通过 auth 模块获取密钥 secretKey := h.service.GetJWTSecretKey() // 调用 DecodeTokenStatic 方法解析 token encryptedPhone, err := auth_middleware.DecodeTokenStatic(req.Token, []byte(secretKey)) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{ "encryptedPhone": encryptedPhone, }) }