194 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			194 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|  | package entities | |||
|  | 
 | |||
|  | import ( | |||
|  | 	"crypto/rand" | |||
|  | 	"encoding/hex" | |||
|  | 	"errors" | |||
|  | 	"io" | |||
|  | 	"net" | |||
|  | 	"time" | |||
|  | 
 | |||
|  | 	"github.com/google/uuid" | |||
|  | 	"gorm.io/gorm" | |||
|  | ) | |||
|  | 
 | |||
|  | // ApiUserStatus API用户状态 | |||
|  | const ( | |||
|  | 	ApiUserStatusNormal = "normal" | |||
|  | 	ApiUserStatusFrozen = "frozen" | |||
|  | ) | |||
|  | 
 | |||
|  | // ApiUser API用户(聚合根) | |||
|  | type ApiUser struct { | |||
|  | 	ID        string    `gorm:"primaryKey;type:varchar(64)" json:"id"` | |||
|  | 	UserId    string    `gorm:"type:varchar(36);not null;uniqueIndex" json:"user_id"` | |||
|  | 	AccessId  string    `gorm:"type:varchar(64);not null;uniqueIndex" json:"access_id"` | |||
|  | 	SecretKey string    `gorm:"type:varchar(128);not null" json:"secret_key"` | |||
|  | 	Status    string    `gorm:"type:varchar(20);not null;default:'normal'" json:"status"` | |||
|  | 	WhiteList []string  `gorm:"type:json;serializer:json;default:'[]'" json:"white_list"` // 支持多个白名单 | |||
|  | 	CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"` | |||
|  | 	UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"` | |||
|  | } | |||
|  | 
 | |||
|  | // IsWhiteListed 校验IP/域名是否在白名单 | |||
|  | func (u *ApiUser) IsWhiteListed(target string) bool { | |||
|  | 	for _, w := range u.WhiteList { | |||
|  | 		if w == target { | |||
|  | 			return true | |||
|  | 		} | |||
|  | 	} | |||
|  | 	return false | |||
|  | } | |||
|  | 
 | |||
|  | // IsActive 是否可用 | |||
|  | func (u *ApiUser) IsActive() bool { | |||
|  | 	return u.Status == ApiUserStatusNormal | |||
|  | } | |||
|  | 
 | |||
|  | // IsFrozen 是否冻结 | |||
|  | func (u *ApiUser) IsFrozen() bool { | |||
|  | 	return u.Status == ApiUserStatusFrozen | |||
|  | } | |||
|  | 
 | |||
|  | // NewApiUser 工厂方法 | |||
|  | func NewApiUser(userId string) (*ApiUser, error) { | |||
|  | 	if userId == "" { | |||
|  | 		return nil, errors.New("用户ID不能为空") | |||
|  | 	} | |||
|  | 	accessId, err := GenerateSecretId() | |||
|  | 	if err != nil { | |||
|  | 		return nil, err | |||
|  | 	} | |||
|  | 	secretKey, err := GenerateSecretKey() | |||
|  | 	if err != nil { | |||
|  | 		return nil, err | |||
|  | 	} | |||
|  | 	return &ApiUser{ | |||
|  | 		ID:        uuid.New().String(), | |||
|  | 		UserId:    userId, | |||
|  | 		AccessId:  accessId, | |||
|  | 		SecretKey: secretKey, | |||
|  | 		Status:    ApiUserStatusNormal, | |||
|  | 		WhiteList: []string{}, | |||
|  | 	}, nil | |||
|  | } | |||
|  | 
 | |||
|  | // 领域行为 | |||
|  | func (u *ApiUser) Freeze() { | |||
|  | 	u.Status = ApiUserStatusFrozen | |||
|  | } | |||
|  | func (u *ApiUser) Unfreeze() { | |||
|  | 	u.Status = ApiUserStatusNormal | |||
|  | } | |||
|  | func (u *ApiUser) UpdateWhiteList(list []string) { | |||
|  | 	u.WhiteList = list | |||
|  | } | |||
|  | 
 | |||
|  | // AddToWhiteList 新增白名单项(防御性校验) | |||
|  | func (u *ApiUser) AddToWhiteList(entry string) error { | |||
|  | 	if len(u.WhiteList) >= 10 { | |||
|  | 		return errors.New("白名单最多只能有10个") | |||
|  | 	} | |||
|  | 	if net.ParseIP(entry) == nil { | |||
|  | 		return errors.New("非法IP") | |||
|  | 	} | |||
|  | 	for _, w := range u.WhiteList { | |||
|  | 		if w == entry { | |||
|  | 			return errors.New("白名单已存在") | |||
|  | 		} | |||
|  | 	} | |||
|  | 	u.WhiteList = append(u.WhiteList, entry) | |||
|  | 	return nil | |||
|  | } | |||
|  | 
 | |||
|  | // BeforeUpdate GORM钩子:更新前确保WhiteList不为nil | |||
|  | func (u *ApiUser) BeforeUpdate(tx *gorm.DB) error { | |||
|  | 	if u.WhiteList == nil { | |||
|  | 		u.WhiteList = []string{} | |||
|  | 	} | |||
|  | 	return nil | |||
|  | } | |||
|  | 
 | |||
|  | // RemoveFromWhiteList 删除白名单项 | |||
|  | func (u *ApiUser) RemoveFromWhiteList(entry string) error { | |||
|  | 	newList := make([]string, 0, len(u.WhiteList)) | |||
|  | 	for _, w := range u.WhiteList { | |||
|  | 		if w != entry { | |||
|  | 			newList = append(newList, w) | |||
|  | 		} | |||
|  | 	} | |||
|  | 	if len(newList) == len(u.WhiteList) { | |||
|  | 		return errors.New("白名单不存在") | |||
|  | 	} | |||
|  | 	u.WhiteList = newList | |||
|  | 	return nil | |||
|  | } | |||
|  | 
 | |||
|  | // Validate 校验ApiUser聚合根的业务规则 | |||
|  | func (u *ApiUser) Validate() error { | |||
|  | 	if u.UserId == "" { | |||
|  | 		return errors.New("用户ID不能为空") | |||
|  | 	} | |||
|  | 	if u.AccessId == "" { | |||
|  | 		return errors.New("AccessId不能为空") | |||
|  | 	} | |||
|  | 	if u.SecretKey == "" { | |||
|  | 		return errors.New("SecretKey不能为空") | |||
|  | 	} | |||
|  | 	switch u.Status { | |||
|  | 	case ApiUserStatusNormal, ApiUserStatusFrozen: | |||
|  | 		// ok | |||
|  | 	default: | |||
|  | 		return errors.New("无效的用户状态") | |||
|  | 	} | |||
|  | 	if len(u.WhiteList) > 10 { | |||
|  | 		return errors.New("白名单最多只能有10个") | |||
|  | 	} | |||
|  | 	for _, ip := range u.WhiteList { | |||
|  | 		if net.ParseIP(ip) == nil { | |||
|  | 			return errors.New("白名单项必须为合法IP地址: " + ip) | |||
|  | 		} | |||
|  | 	} | |||
|  | 	return nil | |||
|  | } | |||
|  | 
 | |||
|  | // 生成AES-128密钥的函数,符合市面规范 | |||
|  | func GenerateSecretKey() (string, error) { | |||
|  | 	key := make([]byte, 16) // 16字节密钥 | |||
|  | 	_, err := io.ReadFull(rand.Reader, key) | |||
|  | 	if err != nil { | |||
|  | 		return "", err | |||
|  | 	} | |||
|  | 	return hex.EncodeToString(key), nil | |||
|  | } | |||
|  | 
 | |||
|  | func GenerateSecretId() (string, error) { | |||
|  | 	// 创建一个字节数组,用于存储随机数据 | |||
|  | 	bytes := make([]byte, 8) // 因为每个字节表示两个16进制字符 | |||
|  | 
 | |||
|  | 	// 读取随机字节到数组中 | |||
|  | 	_, err := rand.Read(bytes) | |||
|  | 	if err != nil { | |||
|  | 		return "", err | |||
|  | 	} | |||
|  | 
 | |||
|  | 	// 将字节数组转换为16进制字符串 | |||
|  | 	return hex.EncodeToString(bytes), nil | |||
|  | } | |||
|  | 
 | |||
|  | // TableName 指定数据库表名 | |||
|  | func (ApiUser) TableName() string { | |||
|  | 	return "api_users" | |||
|  | } | |||
|  | 
 | |||
|  | // BeforeCreate GORM钩子:创建前自动生成UUID并确保WhiteList不为nil | |||
|  | func (c *ApiUser) BeforeCreate(tx *gorm.DB) error { | |||
|  | 	if c.ID == "" { | |||
|  | 		c.ID = uuid.New().String() | |||
|  | 	} | |||
|  | 	if c.WhiteList == nil { | |||
|  | 		c.WhiteList = []string{} | |||
|  | 	} | |||
|  | 	return nil | |||
|  | } |