package auth import ( "context" "encoding/json" "time" authModel "gitea.loveuer.com/loveuer/cluster/pkg/model/auth" "gitea.loveuer.com/loveuer/cluster/pkg/resp" "gitea.loveuer.com/loveuer/cluster/pkg/tool" "github.com/gofiber/fiber/v3" "github.com/golang-jwt/jwt/v5" "gorm.io/gorm" ) const ( JWTSecret = "cluster-secret-key-change-in-production" TokenDuration = 7 * 24 * time.Hour ) type LoginRequest struct { Username string `json:"username"` Password string `json:"password"` } type LoginResponse struct { Token string `json:"token"` Username string `json:"username"` Nickname string `json:"nickname"` Role string `json:"role"` } type Claims struct { UserID uint `json:"user_id"` Username string `json:"username"` Role string `json:"role"` jwt.RegisteredClaims } func Login(ctx context.Context, db *gorm.DB) fiber.Handler { return func(c fiber.Ctx) error { var req LoginRequest body := c.Body() if len(body) == 0 { return resp.R400(c, "EMPTY_BODY", nil, "request body is empty") } if err := json.Unmarshal(body, &req); err != nil { return resp.R400(c, "INVALID_REQUEST", nil, "invalid request body") } if req.Username == "" || req.Password == "" { return resp.R400(c, "MISSING_CREDENTIALS", nil, "username and password are required") } var user authModel.User if err := db.Where("username = ?", req.Username).First(&user).Error; err != nil { if err == gorm.ErrRecordNotFound { return resp.R401(c, "INVALID_CREDENTIALS", nil, "invalid username or password") } return resp.R500(c, "", nil, err.Error()) } if user.Status != "active" { return resp.R403(c, "USER_INACTIVE", nil, "user account is inactive") } if !tool.ComparePassword(req.Password, user.Password) { return resp.R401(c, "INVALID_CREDENTIALS", nil, "invalid username or password") } claims := &Claims{ UserID: user.ID, Username: user.Username, Role: user.Role, RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(time.Now().Add(TokenDuration)), IssuedAt: jwt.NewNumericDate(time.Now()), NotBefore: jwt.NewNumericDate(time.Now()), }, } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) tokenString, err := token.SignedString([]byte(JWTSecret)) if err != nil { return resp.R500(c, "", nil, "failed to generate token") } return resp.R200(c, LoginResponse{ Token: tokenString, Username: user.Username, Nickname: user.Nickname, Role: user.Role, }) } }