Files
2025-09-30 22:32:30 +08:00

89 lines
2.7 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package models
import (
"database/sql/driver"
"encoding/json"
"errors"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
// ContactInfo 存储用户的多种联系方式
// 使用 jsonb 类型存入数据库
type ContactInfo struct {
Email string `json:"email,omitempty"`
Phone string `json:"phone,omitempty"`
WeChat string `json:"wechat,omitempty"`
Feishu string `json:"feishu,omitempty"`
}
// Scan 实现 sql.Scanner 接口,用于从数据库读取 JSONB 数据
func (ci *ContactInfo) Scan(value interface{}) error {
if value == nil {
*ci = ContactInfo{} // 如果数据库值为 NULL则初始化为空结构体
return nil
}
bytes, ok := value.([]byte)
if !ok {
return errors.New("type assertion to []byte failed for ContactInfo")
}
return json.Unmarshal(bytes, ci)
}
// Value 实现 driver.Valuer 接口,用于将 ContactInfo 写入数据库为 JSONB 数据
func (ci ContactInfo) Value() (driver.Value, error) {
return json.Marshal(ci)
}
// User 代表系统中的用户模型
type User struct {
// gorm.Model 内嵌了 ID, CreatedAt, UpdatedAt, 和 DeletedAt
// DeletedAt 字段的存在自动为 GORM 开启了软删除模式
gorm.Model
// Username 是用户的登录名,应该是唯一的
// 修正了 gorm 标签的拼写错误 (移除了 gorm 后面的冒号)
Username string `gorm:"unique;not null" json:"username"`
// Password 存储的是加密后的密码哈希,而不是明文
// json:"-" 标签确保此字段在序列化为 JSON 时被忽略,防止密码泄露
Password string `gorm:"not null" json:"-"`
// Contact 存储用户的联系方式,以 JSONB 格式存入数据库
Contact ContactInfo `gorm:"type:jsonb" json:"contact"`
}
// TableName 自定义 User 模型对应的数据库表名
// GORM 默认会使用复数形式 "users",但显式定义是一种好习惯
func (User) TableName() string {
return "users"
}
// --- GORM Hooks ---
// BeforeCreate 是一个 GORM 钩子,在创建用户记录前自动调用。
// 这是哈希初始密码最可靠的地方。
func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
// 如果密码不为空,则执行哈希
if u.Password != "" {
// 使用 bcrypt 对密码进行哈希
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost)
if err != nil {
return err
}
// 将明文密码替换为哈希值
u.Password = string(hashedPassword)
}
return nil
}
// --- Helper Methods ---
// CheckPassword 用于验证输入的明文密码是否与数据库中存储的哈希匹配
func (u *User) CheckPassword(plainPassword string) bool {
// bcrypt.CompareHashAndPassword 会安全地比较哈希和明文,能有效防止时序攻击
err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(plainPassword))
return err == nil
}