2025-11-28 23:30:49 +08:00
|
|
|
|
package model
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
2025-12-02 10:33:19 +08:00
|
|
|
|
"crypto/rand"
|
2025-11-28 23:30:49 +08:00
|
|
|
|
"fmt"
|
2025-12-02 10:33:19 +08:00
|
|
|
|
"math/big"
|
|
|
|
|
|
|
|
|
|
|
|
"golang.org/x/crypto/bcrypt"
|
2025-11-28 23:30:49 +08:00
|
|
|
|
"gorm.io/gorm"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 定义随机字符集
|
|
|
|
|
|
const passwordChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
|
|
|
|
|
|
|
|
|
|
|
// Yggdrasil ygg密码与用户id绑定
|
|
|
|
|
|
type Yggdrasil struct {
|
|
|
|
|
|
ID int64 `gorm:"column:id;primaryKey;not null" json:"id"`
|
2025-12-02 10:33:19 +08:00
|
|
|
|
Password string `gorm:"column:password;type:varchar(255);not null" json:"-"` // 加密后的密码,不返回给前端
|
2025-11-28 23:30:49 +08:00
|
|
|
|
// 关联 - Yggdrasil的ID引用User的ID,但不自动创建外键约束(避免循环依赖)
|
|
|
|
|
|
User *User `gorm:"foreignKey:ID;references:ID;constraint:OnDelete:CASCADE,OnUpdate:CASCADE" json:"user,omitempty"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-02 10:33:19 +08:00
|
|
|
|
func (Yggdrasil) TableName() string { return "yggdrasil" }
|
2025-11-28 23:30:49 +08:00
|
|
|
|
|
2025-12-02 10:33:19 +08:00
|
|
|
|
// AfterCreate User创建后自动同步生成Yggdrasil密码记录
|
2025-11-28 23:30:49 +08:00
|
|
|
|
func (u *User) AfterCreate(tx *gorm.DB) error {
|
2025-12-02 10:33:19 +08:00
|
|
|
|
// 生成随机明文密码
|
|
|
|
|
|
plainPassword := GenerateRandomPassword(16)
|
|
|
|
|
|
|
|
|
|
|
|
// 使用 bcrypt 加密密码
|
|
|
|
|
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(plainPassword), bcrypt.DefaultCost)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Errorf("密码加密失败: %w", err)
|
|
|
|
|
|
}
|
2025-11-28 23:30:49 +08:00
|
|
|
|
|
2025-12-02 10:33:19 +08:00
|
|
|
|
// 创建Yggdrasil记录(存储加密后的密码)
|
|
|
|
|
|
ygg := Yggdrasil{
|
|
|
|
|
|
ID: u.ID,
|
|
|
|
|
|
Password: string(hashedPassword),
|
2025-11-28 23:30:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-02 10:33:19 +08:00
|
|
|
|
if err := tx.Create(&ygg).Error; err != nil {
|
|
|
|
|
|
return fmt.Errorf("同步生成Yggdrasil密码失败: %w", err)
|
2025-11-28 23:30:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-02 10:33:19 +08:00
|
|
|
|
// GenerateRandomPassword 生成指定长度的安全随机字符串
|
2025-11-28 23:30:49 +08:00
|
|
|
|
func GenerateRandomPassword(length int) string {
|
|
|
|
|
|
b := make([]byte, length)
|
|
|
|
|
|
for i := range b {
|
2025-12-02 10:33:19 +08:00
|
|
|
|
num, err := rand.Int(rand.Reader, big.NewInt(int64(len(passwordChars))))
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
// 如果安全随机数生成失败,使用固定值(极端情况下的降级处理)
|
|
|
|
|
|
b[i] = passwordChars[0]
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
b[i] = passwordChars[num.Int64()]
|
2025-11-28 23:30:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
return string(b)
|
|
|
|
|
|
}
|