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) { var req RegisterRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": 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": "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": "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": "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": err.Error()}) return } user, err := h.service.GetUserByUsername(c.Request.Context(), req.Username) if err != nil { c.JSON(http.StatusUnauthorized, gin.H{ "error": "Invalid username or password", }) return } // 验证密码 err = bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(req.Password)) if err != nil { c.JSON(http.StatusUnauthorized, gin.H{ "error": "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": "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": "Failed to generate token", }) return } c.JSON(http.StatusOK, AuthResponse{Token: tokenString}) }