fix: 系统性修复安全问题、性能问题和错误处理

安全问题修复:
- X-Forwarded-For越界检查(auth.go)
- checkTokenStatus Context参数传递(auth.go)
- Type Assertion安全检查(auth.go)

性能问题修复:
- TokenCache过期清理机制
- BruteForceProtection过期清理
- InMemoryIdempotencyStore过期清理

错误处理修复:
- AuditStore.Emit返回error
- domain层emitAudit辅助方法
- List方法返回空slice而非nil
- 金额/价格负数验证

架构一致性:
- 统一使用model.RoleHierarchyLevels

新增功能:
- Alert API完整实现(CRUD+Resolve)
- pkg/error错误码集中管理
This commit is contained in:
Your Name
2026-04-07 07:41:25 +08:00
parent 12ce4913cd
commit d5b5a8ece0
21 changed files with 2321 additions and 83 deletions

View File

@@ -0,0 +1,195 @@
package model
import (
"time"
"github.com/google/uuid"
)
// 告警级别常量
const (
AlertLevelInfo = "info"
AlertLevelWarning = "warning"
AlertLevelError = "error"
AlertLevelCritical = "critical"
)
// 告警状态常量
const (
AlertStatusActive = "active"
AlertStatusResolved = "resolved"
AlertStatusAcknowledged = "acknowledged"
AlertStatusSuppressed = "suppressed"
)
// 告警类型常量
const (
AlertTypeSecurity = "security"
AlertTypeInvariant = "invariant"
AlertTypeCredential = "credential"
AlertTypeAuthentication = "authentication"
AlertTypeAuthorization = "authorization"
AlertTypeQuota = "quota"
)
// Alert 告警
type Alert struct {
// 基础标识
AlertID string `json:"alert_id"` // 告警唯一ID
AlertName string `json:"alert_name"` // 告警名称
AlertType string `json:"alert_type"` // 告警类型 (security/invariant/credential/etc.)
AlertLevel string `json:"alert_level"` // 告警级别 (info/warning/error/critical)
TenantID int64 `json:"tenant_id"` // 租户ID
SupplierID int64 `json:"supplier_id,omitempty"` // 供应商ID可选
// 告警内容
Title string `json:"title"` // 告警标题
Message string `json:"message"` // 告警消息
Description string `json:"description,omitempty"` // 详细描述
// 关联事件
EventID string `json:"event_id,omitempty"` // 关联的事件ID
EventIDs []string `json:"event_ids,omitempty"` // 关联的事件ID列表多个
// 触发条件
TriggerCondition string `json:"trigger_condition,omitempty"` // 触发条件
Threshold float64 `json:"threshold,omitempty"` // 阈值
CurrentValue float64 `json:"current_value,omitempty"` // 当前值
// 状态
Status string `json:"status"` // 状态 (active/resolved/acknowledged/suppressed)
ResolvedAt *time.Time `json:"resolved_at,omitempty"` // 解决时间
ResolvedBy string `json:"resolved_by,omitempty"` // 解决人
ResolveNote string `json:"resolve_note,omitempty"` // 解决备注
// 通知
NotifyEnabled bool `json:"notify_enabled"` // 是否启用通知
NotifyChannels []string `json:"notify_channels,omitempty"` // 通知渠道 (email/sms/webhook/etc.)
// 时间戳
CreatedAt time.Time `json:"created_at"` // 创建时间
UpdatedAt time.Time `json:"updated_at"` // 更新时间
FirstSeenAt time.Time `json:"first_seen_at"` // 首次出现时间
LastSeenAt time.Time `json:"last_seen_at"` // 最后出现时间
// 元数据
Metadata map[string]any `json:"metadata,omitempty"` // 扩展元数据
Tags []string `json:"tags,omitempty"` // 标签
}
// NewAlert 创建新告警
func NewAlert(alertName, alertType, alertLevel, tenantID string, title, message string) *Alert {
now := time.Now()
return &Alert{
AlertID: generateAlertID(),
AlertName: alertName,
AlertType: alertType,
AlertLevel: alertLevel,
TenantID: parseTenantID(tenantID),
Title: title,
Message: message,
Status: AlertStatusActive,
NotifyEnabled: true,
CreatedAt: now,
UpdatedAt: now,
FirstSeenAt: now,
LastSeenAt: now,
Metadata: make(map[string]any),
Tags: []string{},
}
}
// generateAlertID 生成告警ID
func generateAlertID() string {
return "ALT-" + uuid.New().String()[:8]
}
// parseTenantID 解析租户ID
func parseTenantID(tenantID string) int64 {
var id int64
for _, c := range tenantID {
if c >= '0' && c <= '9' {
id = id*10 + int64(c-'0')
}
}
return id
}
// IsActive 检查告警是否处于活跃状态
func (a *Alert) IsActive() bool {
return a.Status == AlertStatusActive
}
// IsResolved 检查告警是否已解决
func (a *Alert) IsResolved() bool {
return a.Status == AlertStatusResolved
}
// Resolve 解决告警
func (a *Alert) Resolve(resolvedBy, note string) {
now := time.Now()
a.Status = AlertStatusResolved
a.ResolvedAt = &now
a.ResolvedBy = resolvedBy
a.ResolveNote = note
a.UpdatedAt = now
}
// Acknowledge 确认告警
func (a *Alert) Acknowledge() {
a.Status = AlertStatusAcknowledged
a.UpdatedAt = time.Now()
}
// Suppress 抑制告警
func (a *Alert) Suppress() {
a.Status = AlertStatusSuppressed
a.UpdatedAt = time.Now()
}
// UpdateLastSeen 更新最后出现时间
func (a *Alert) UpdateLastSeen() {
a.LastSeenAt = time.Now()
a.UpdatedAt = time.Now()
}
// AddEventID 添加关联事件ID
func (a *Alert) AddEventID(eventID string) {
a.EventIDs = append(a.EventIDs, eventID)
if a.EventID == "" {
a.EventID = eventID
}
a.UpdateLastSeen()
}
// SetMetadata 设置元数据
func (a *Alert) SetMetadata(key string, value any) {
if a.Metadata == nil {
a.Metadata = make(map[string]any)
}
a.Metadata[key] = value
}
// AddTag 添加标签
func (a *Alert) AddTag(tag string) {
for _, t := range a.Tags {
if t == tag {
return
}
}
a.Tags = append(a.Tags, tag)
}
// AlertFilter 告警查询过滤器
type AlertFilter struct {
TenantID int64
SupplierID int64
AlertType string
AlertLevel string
Status string
StartTime time.Time
EndTime time.Time
Keywords string // 关键字搜索(标题/消息)
Limit int
Offset int
}