You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

171 lines
4.1 KiB
Go

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"
)
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
}
openid := jwtfx.GetOpenid(c)
if openid == "" {
c.JSON(http.StatusInternalServerError, "openid为空")
return
}
// 生成短信验证码
captcha, err := h.captchaService.GenerateSmsCaptcha(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)
}
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, jwtfx.GetOpenid(c))
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)
}
}