Files
tyapi-server/internal/domains/api/entities/api_user.go
2025-07-28 01:46:39 +08:00

194 lines
4.5 KiB
Go
Raw 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 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
}