package handler import ( "errors" "net/http" "strings" "juhe-factory/api/internal/model" "juhe-factory/api/internal/service" "github.com/gin-gonic/gin" ) const adminContextKey = "admin_user" type AdminAuth struct{ service *service.Auth } func NewAdminAuth(service *service.Auth) *AdminAuth { return &AdminAuth{service: service} } func (h *AdminAuth) Login(c *gin.Context) { var body struct { Username string `json:"username" binding:"required"` Password string `json:"password" binding:"required"` } if err := c.ShouldBindJSON(&body); err != nil { fail(c, http.StatusBadRequest, "invalid_request", "请输入管理员账号和密码") return } pair, err := h.service.Login(body.Username, body.Password) if err != nil { fail(c, http.StatusUnauthorized, "invalid_credentials", err.Error()) return } c.JSON(http.StatusOK, gin.H{"data": pair}) } func (h *AdminAuth) Refresh(c *gin.Context) { var body struct { RefreshToken string `json:"refresh_token" binding:"required"` } if err := c.ShouldBindJSON(&body); err != nil { fail(c, http.StatusBadRequest, "invalid_request", "缺少刷新令牌") return } pair, err := h.service.Refresh(body.RefreshToken) if err != nil { fail(c, http.StatusUnauthorized, "invalid_refresh_token", err.Error()) return } c.JSON(http.StatusOK, gin.H{"data": pair}) } func (h *AdminAuth) Logout(c *gin.Context) { var body struct { RefreshToken string `json:"refresh_token"` } _ = c.ShouldBindJSON(&body) if err := h.service.Logout(body.RefreshToken); err != nil { fail(c, http.StatusInternalServerError, "logout_failed", "退出登录失败") return } c.Status(http.StatusNoContent) } func (h *AdminAuth) ChangePassword(c *gin.Context) { var body struct { CurrentPassword string `json:"current_password" binding:"required"` NewPassword string `json:"new_password" binding:"required"` ConfirmPassword string `json:"confirm_password" binding:"required"` } if err := c.ShouldBindJSON(&body); err != nil { fail(c, http.StatusBadRequest, "invalid_request", "请完整填写密码") return } admin := currentAdmin(c) if err := h.service.ChangePassword(admin.ID, body.CurrentPassword, body.NewPassword, body.ConfirmPassword); err != nil { if errors.Is(err, service.ErrReauthFailed) || errors.Is(err, service.ErrAdminPasswordConfirmation) || errors.Is(err, service.ErrAdminPasswordLength) { _ = h.service.Audit(admin, "password_change_failed", "admin-auth", admin.ID.String(), err.Error(), c.ClientIP(), c.GetString("trace_id"), nil) fail(c, http.StatusBadRequest, "password_invalid", err.Error()) return } fail(c, http.StatusInternalServerError, "password_update_failed", "密码修改失败,请稍后重试") return } _ = h.service.Audit(admin, "password_changed", "admin-auth", admin.ID.String(), "", c.ClientIP(), c.GetString("trace_id"), nil) c.Status(http.StatusNoContent) } func (h *AdminAuth) Middleware() gin.HandlerFunc { return func(c *gin.Context) { raw := strings.TrimSpace(strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer ")) admin, err := h.service.Authenticate(raw) if err != nil { fail(c, http.StatusUnauthorized, "unauthorized", err.Error()) c.Abort() return } c.Set(adminContextKey, admin) c.Next() } } func currentAdmin(c *gin.Context) *model.AdminUser { value, _ := c.Get(adminContextKey) admin, _ := value.(*model.AdminUser) return admin } func fail(c *gin.Context, status int, code, message string) { c.JSON(status, gin.H{"code": code, "message": message, "trace_id": c.GetString("trace_id")}) }