package entities import ( "errors" "fmt" "regexp" "time" "github.com/google/uuid" "golang.org/x/crypto/bcrypt" "gorm.io/gorm" ) // User 用户实体 // 系统用户的核心信息,提供基础的账户管理功能 // 支持手机号登录,密码加密存储,实现Entity接口便于统一管理 type User struct { // 基础标识 ID string `gorm:"primaryKey;type:varchar(36)" json:"id" comment:"用户唯一标识"` Phone string `gorm:"uniqueIndex;type:varchar(20);not null" json:"phone" comment:"手机号码(登录账号)"` Password string `gorm:"type:varchar(255);not null" json:"-" comment:"登录密码(加密存储,不返回前端)"` // 时间戳字段 CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at" comment:"创建时间"` UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at" comment:"更新时间"` DeletedAt gorm.DeletedAt `gorm:"index" json:"-" comment:"软删除时间"` // 关联关系 EnterpriseInfo *EnterpriseInfo `gorm:"foreignKey:UserID" json:"enterprise_info,omitempty" comment:"企业信息(认证后获得)"` } // BeforeCreate GORM钩子:创建前自动生成UUID func (u *User) BeforeCreate(tx *gorm.DB) error { if u.ID == "" { u.ID = uuid.New().String() } return nil } // 实现 Entity 接口 - 提供统一的实体管理接口 // GetID 获取实体唯一标识 func (u *User) GetID() string { return u.ID } // GetCreatedAt 获取创建时间 func (u *User) GetCreatedAt() time.Time { return u.CreatedAt } // GetUpdatedAt 获取更新时间 func (u *User) GetUpdatedAt() time.Time { return u.UpdatedAt } // Validate 验证用户信息 // 检查用户必填字段是否完整,确保数据的有效性 func (u *User) Validate() error { if u.Phone == "" { return NewValidationError("手机号不能为空") } if u.Password == "" { return NewValidationError("密码不能为空") } // 验证手机号格式 if !u.IsValidPhone() { return NewValidationError("手机号格式无效") } // 验证密码强度 if err := u.validatePasswordStrength(u.Password); err != nil { return err } return nil } // ================ 业务方法 ================ // ChangePassword 修改密码 // 验证旧密码,检查新密码强度,更新密码 func (u *User) ChangePassword(oldPassword, newPassword, confirmPassword string) error { // 1. 验证确认密码 if newPassword != confirmPassword { return NewValidationError("新密码和确认新密码不匹配") } // 2. 验证旧密码 if !u.CheckPassword(oldPassword) { return NewValidationError("当前密码错误") } // 3. 验证新密码强度 if err := u.validatePasswordStrength(newPassword); err != nil { return err } // 4. 检查新密码不能与旧密码相同 if u.CheckPassword(newPassword) { return NewValidationError("新密码不能与当前密码相同") } // 5. 更新密码 hashedPassword, err := u.hashPassword(newPassword) if err != nil { return fmt.Errorf("密码加密失败: %w", err) } u.Password = hashedPassword return nil } // CheckPassword 验证密码是否正确 func (u *User) CheckPassword(password string) bool { err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password)) return err == nil } // SetPassword 设置密码(用于注册或重置密码) func (u *User) SetPassword(password string) error { // 验证密码强度 if err := u.validatePasswordStrength(password); err != nil { return err } // 加密密码 hashedPassword, err := u.hashPassword(password) if err != nil { return fmt.Errorf("密码加密失败: %w", err) } u.Password = hashedPassword return nil } // ResetPassword 重置密码(忘记密码时使用) func (u *User) ResetPassword(newPassword, confirmPassword string) error { // 1. 验证确认密码 if newPassword != confirmPassword { return NewValidationError("新密码和确认新密码不匹配") } // 2. 验证新密码强度 if err := u.validatePasswordStrength(newPassword); err != nil { return err } // 3. 更新密码 hashedPassword, err := u.hashPassword(newPassword) if err != nil { return fmt.Errorf("密码加密失败: %w", err) } u.Password = hashedPassword return nil } // CanLogin 检查用户是否可以登录 func (u *User) CanLogin() bool { // 检查用户是否被删除 if !u.DeletedAt.Time.IsZero() { return false } // 检查必要字段是否存在 if u.Phone == "" || u.Password == "" { return false } return true } // IsActive 检查用户是否处于活跃状态 func (u *User) IsActive() bool { return u.DeletedAt.Time.IsZero() } // IsDeleted 检查用户是否已被删除 func (u *User) IsDeleted() bool { return !u.DeletedAt.Time.IsZero() } // ================ 手机号相关方法 ================ // IsValidPhone 验证手机号格式 func (u *User) IsValidPhone() bool { return IsValidPhoneFormat(u.Phone) } // SetPhone 设置手机号 func (u *User) SetPhone(phone string) error { if !IsValidPhoneFormat(phone) { return NewValidationError("手机号格式无效") } u.Phone = phone return nil } // GetMaskedPhone 获取脱敏的手机号 func (u *User) GetMaskedPhone() string { if len(u.Phone) < 7 { return u.Phone } return u.Phone[:3] + "****" + u.Phone[len(u.Phone)-4:] } // ================ 私有辅助方法 ================ // hashPassword 加密密码 func (u *User) hashPassword(password string) (string, error) { hashedBytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { return "", err } return string(hashedBytes), nil } // validatePasswordStrength 验证密码强度 func (u *User) validatePasswordStrength(password string) error { if len(password) < 8 { return NewValidationError("密码长度至少8位") } if len(password) > 128 { return NewValidationError("密码长度不能超过128位") } // 检查是否包含数字 hasDigit := regexp.MustCompile(`[0-9]`).MatchString(password) if !hasDigit { return NewValidationError("密码必须包含数字") } // 检查是否包含字母 hasLetter := regexp.MustCompile(`[a-zA-Z]`).MatchString(password) if !hasLetter { return NewValidationError("密码必须包含字母") } // 检查是否包含特殊字符(可选,可以根据需求调整) hasSpecial := regexp.MustCompile(`[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]`).MatchString(password) if !hasSpecial { return NewValidationError("密码必须包含特殊字符") } return nil } // ================ 静态工具方法 ================ // IsValidPhoneFormat 验证手机号格式(静态方法) func IsValidPhoneFormat(phone string) bool { if phone == "" { return false } // 中国手机号验证(11位数字,以1开头) pattern := `^1[3-9]\d{9}$` matched, _ := regexp.MatchString(pattern, phone) return matched } // NewUser 创建新用户(工厂方法) func NewUser(phone, password string) (*User, error) { user := &User{ ID: "", // 由数据库或调用方设置 Phone: phone, } // 验证手机号 if err := user.SetPhone(phone); err != nil { return nil, err } // 设置密码 if err := user.SetPassword(password); err != nil { return nil, err } return user, nil } // TableName 指定表名 func (User) TableName() string { return "users" } // ValidationError 验证错误 // 自定义验证错误类型,提供结构化的错误信息 type ValidationError struct { Message string } // Error 实现error接口 func (e *ValidationError) Error() string { return e.Message } // NewValidationError 创建新的验证错误 // 工厂方法,用于创建验证错误实例 func NewValidationError(message string) *ValidationError { return &ValidationError{Message: message} } // IsValidationError 检查是否为验证错误 func IsValidationError(err error) bool { var validationErr *ValidationError return errors.As(err, &validationErr) } // UserCache 用户缓存结构体 // 专门用于缓存序列化,包含Password字段 type UserCache struct { // 基础标识 ID string `json:"id" comment:"用户唯一标识"` Phone string `json:"phone" comment:"手机号码(登录账号)"` Password string `json:"password" comment:"登录密码(加密存储)"` // 时间戳字段 CreatedAt time.Time `json:"created_at" comment:"创建时间"` UpdatedAt time.Time `json:"updated_at" comment:"更新时间"` DeletedAt gorm.DeletedAt `json:"deleted_at" comment:"软删除时间"` } // ToCache 转换为缓存结构体 func (u *User) ToCache() *UserCache { return &UserCache{ ID: u.ID, Phone: u.Phone, Password: u.Password, CreatedAt: u.CreatedAt, UpdatedAt: u.UpdatedAt, DeletedAt: u.DeletedAt, } } // FromCache 从缓存结构体转换 func (u *User) FromCache(cache *UserCache) { u.ID = cache.ID u.Phone = cache.Phone u.Password = cache.Password u.CreatedAt = cache.CreatedAt u.UpdatedAt = cache.UpdatedAt u.DeletedAt = cache.DeletedAt }