package handler import ( "net/http" "time" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v5" "github.com/rs/zerolog/log" "golang.org/x/crypto/bcrypt" ) type RegisterRequest struct { Username string `json:"username" binding:"required"` Email string `json:"email" binding:"required,email"` Password string `json:"password" binding:"required,min=8"` Role string `json:"role" binding:"required,oneof=admin editor contributor"` } type LoginRequest struct { Username string `json:"username" binding:"required,min=3,max=32"` Password string `json:"password" binding:"required"` } type AuthResponse struct { Token string `json:"token"` } func (h *Handler) Register(c *gin.Context) { // 检查是否启用注册功能 if !h.config.Auth.Registration.Enabled { message := h.config.Auth.Registration.Message if message == "" { message = "Registration is currently disabled" } c.JSON(http.StatusForbidden, gin.H{ "error": gin.H{ "code": "REGISTRATION_DISABLED", "message": message, }, }) return } var req RegisterRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": gin.H{ "code": "INVALID_REQUEST", "message": err.Error(), }, }) return } user, err := h.service.CreateUser(c.Request.Context(), req.Username, req.Email, req.Password, req.Role) if err != nil { log.Error().Err(err).Msg("Failed to create user") c.JSON(http.StatusInternalServerError, gin.H{ "error": gin.H{ "code": "CREATE_USER_FAILED", "message": "Failed to create user", }, }) return } // Get user roles roles, err := h.service.GetUserRoles(c.Request.Context(), user.ID) if err != nil { log.Error().Err(err).Msg("Failed to get user roles") c.JSON(http.StatusInternalServerError, gin.H{ "error": gin.H{ "code": "GET_ROLES_FAILED", "message": "Failed to get user roles", }, }) return } // Extract role names for JWT roleNames := make([]string, len(roles)) for i, r := range roles { roleNames[i] = r.Name } // Generate JWT token token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "sub": user.ID, "roles": roleNames, "exp": time.Now().Add(24 * time.Hour).Unix(), }) tokenString, err := token.SignedString([]byte(h.cfg.JWT.Secret)) if err != nil { log.Error().Err(err).Msg("Failed to generate token") c.JSON(http.StatusInternalServerError, gin.H{ "error": gin.H{ "code": "GENERATE_TOKEN_FAILED", "message": "Failed to generate token", }, }) return } c.JSON(http.StatusCreated, AuthResponse{Token: tokenString}) } func (h *Handler) Login(c *gin.Context) { var req LoginRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": gin.H{ "code": "INVALID_REQUEST", "message": err.Error(), }, }) return } user, err := h.service.GetUserByUsername(c.Request.Context(), req.Username) if err != nil { c.JSON(http.StatusUnauthorized, gin.H{ "error": gin.H{ "code": "INVALID_CREDENTIALS", "message": "Invalid username or password", }, }) return } // 验证密码 err = bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(req.Password)) if err != nil { c.JSON(http.StatusUnauthorized, gin.H{ "error": gin.H{ "code": "INVALID_CREDENTIALS", "message": "Invalid username or password", }, }) return } // Get user roles roles, err := h.service.GetUserRoles(c.Request.Context(), user.ID) if err != nil { log.Error().Err(err).Msg("Failed to get user roles") c.JSON(http.StatusInternalServerError, gin.H{ "error": gin.H{ "code": "GET_ROLES_FAILED", "message": "Failed to get user roles", }, }) return } // Extract role names for JWT roleNames := make([]string, len(roles)) for i, r := range roles { roleNames[i] = r.Name } // Generate JWT token token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "sub": user.ID, "roles": roleNames, "exp": time.Now().Add(24 * time.Hour).Unix(), }) tokenString, err := token.SignedString([]byte(h.cfg.JWT.Secret)) if err != nil { log.Error().Err(err).Msg("Failed to generate token") c.JSON(http.StatusInternalServerError, gin.H{ "error": gin.H{ "code": "GENERATE_TOKEN_FAILED", "message": "Failed to generate token", }, }) return } c.JSON(http.StatusOK, AuthResponse{Token: tokenString}) }