feat: 添加种子数据初始化功能,重构多个处理程序以简化错误响应和用户验证

This commit is contained in:
lan
2025-12-02 10:33:19 +08:00
parent bdd2be5dc5
commit 10fdcd916b
30 changed files with 1291 additions and 1778 deletions

View File

@@ -1,10 +1,12 @@
package model
import (
"crypto/rand"
"fmt"
"math/big"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
"math/rand"
"time"
)
// 定义随机字符集
@@ -13,36 +15,47 @@ const passwordChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234
// Yggdrasil ygg密码与用户id绑定
type Yggdrasil struct {
ID int64 `gorm:"column:id;primaryKey;not null" json:"id"`
Password string `gorm:"column:password;not null" json:"password"`
Password string `gorm:"column:password;type:varchar(255);not null" json:"-"` // 加密后的密码,不返回给前端
// 关联 - Yggdrasil的ID引用User的ID但不自动创建外键约束避免循环依赖
User *User `gorm:"foreignKey:ID;references:ID;constraint:OnDelete:CASCADE,OnUpdate:CASCADE" json:"user,omitempty"`
}
func (Yggdrasil) TableName() string { return "Yggdrasil" }
func (Yggdrasil) TableName() string { return "yggdrasil" }
// AfterCreate User创建后自动同步生成GeneratePassword记录
// AfterCreate User创建后自动同步生成Yggdrasil密码记录
func (u *User) AfterCreate(tx *gorm.DB) error {
randomPwd := GenerateRandomPassword(16)
// 生成随机明文密码
plainPassword := GenerateRandomPassword(16)
// 创建GeneratePassword记录
gp := Yggdrasil{
ID: u.ID, // 关联User的ID
Password: randomPwd, // 16位随机密码
// 使用 bcrypt 加密密码
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(plainPassword), bcrypt.DefaultCost)
if err != nil {
return fmt.Errorf("密码加密失败: %w", err)
}
if err := tx.Create(&gp).Error; err != nil {
// 若同步失败,可记录日志或回滚事务(根据业务需求处理)
return fmt.Errorf("同步生成密码失败: %w", err)
// 创建Yggdrasil记录存储加密后的密码
ygg := Yggdrasil{
ID: u.ID,
Password: string(hashedPassword),
}
if err := tx.Create(&ygg).Error; err != nil {
return fmt.Errorf("同步生成Yggdrasil密码失败: %w", err)
}
return nil
}
// GenerateRandomPassword 生成指定长度的随机字符串
// GenerateRandomPassword 生成指定长度的安全随机字符串
func GenerateRandomPassword(length int) string {
rand.Seed(time.Now().UnixNano()) // 初始化随机数种子
b := make([]byte, length)
for i := range b {
b[i] = passwordChars[rand.Intn(len(passwordChars))]
num, err := rand.Int(rand.Reader, big.NewInt(int64(len(passwordChars))))
if err != nil {
// 如果安全随机数生成失败,使用固定值(极端情况下的降级处理)
b[i] = passwordChars[0]
continue
}
b[i] = passwordChars[num.Int64()]
}
return string(b)
}