2026-03-31 13:40:00 +08:00
|
|
|
package audit
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"sync"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// 审计事件
|
|
|
|
|
type Event struct {
|
2026-04-01 13:03:44 +08:00
|
|
|
EventID string `json:"event_id,omitempty"`
|
|
|
|
|
TenantID int64 `json:"tenant_id"`
|
|
|
|
|
ObjectType string `json:"object_type"`
|
|
|
|
|
ObjectID int64 `json:"object_id"`
|
|
|
|
|
Action string `json:"action"`
|
|
|
|
|
BeforeState map[string]any `json:"before_state,omitempty"`
|
|
|
|
|
AfterState map[string]any `json:"after_state,omitempty"`
|
|
|
|
|
RequestID string `json:"request_id,omitempty"`
|
|
|
|
|
ResultCode string `json:"result_code"`
|
|
|
|
|
ClientIP string `json:"client_ip,omitempty"`
|
|
|
|
|
CreatedAt time.Time `json:"created_at"`
|
2026-03-31 13:40:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 审计存储接口
|
|
|
|
|
type AuditStore interface {
|
|
|
|
|
Emit(ctx context.Context, event Event)
|
|
|
|
|
Query(ctx context.Context, filter EventFilter) ([]Event, error)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 事件过滤器
|
|
|
|
|
type EventFilter struct {
|
|
|
|
|
TenantID int64
|
|
|
|
|
ObjectType string
|
|
|
|
|
ObjectID int64
|
|
|
|
|
Action string
|
|
|
|
|
StartDate string
|
|
|
|
|
EndDate string
|
|
|
|
|
Limit int
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 内存审计存储
|
|
|
|
|
type MemoryAuditStore struct {
|
|
|
|
|
mu sync.RWMutex
|
|
|
|
|
events []Event
|
|
|
|
|
nextID int64
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewMemoryAuditStore() *MemoryAuditStore {
|
|
|
|
|
return &MemoryAuditStore{
|
|
|
|
|
events: make([]Event, 0),
|
|
|
|
|
nextID: 1,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *MemoryAuditStore) Emit(ctx context.Context, event Event) {
|
|
|
|
|
s.mu.Lock()
|
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
event.EventID = generateEventID()
|
|
|
|
|
event.CreatedAt = time.Now()
|
|
|
|
|
s.events = append(s.events, event)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *MemoryAuditStore) Query(ctx context.Context, filter EventFilter) ([]Event, error) {
|
|
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
var result []Event
|
|
|
|
|
for _, event := range s.events {
|
|
|
|
|
if filter.TenantID > 0 && event.TenantID != filter.TenantID {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if filter.ObjectType != "" && event.ObjectType != filter.ObjectType {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if filter.ObjectID > 0 && event.ObjectID != filter.ObjectID {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if filter.Action != "" && event.Action != filter.Action {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
result = append(result, event)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 限制返回数量
|
|
|
|
|
if filter.Limit > 0 && len(result) > filter.Limit {
|
|
|
|
|
result = result[:filter.Limit]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func generateEventID() string {
|
|
|
|
|
return time.Now().Format("20060102150405") + "-evt"
|
|
|
|
|
}
|