Files
lijiaoqiao/supply-api/internal/audit/audit.go
Your Name d5b5a8ece0 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错误码集中管理
2026-04-07 07:41:25 +08:00

146 lines
3.4 KiB
Go

package audit
import (
"context"
"fmt"
"sync"
"time"
)
// 审计事件
type Event struct {
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"`
}
// 审计存储接口
type AuditStore interface {
Emit(ctx context.Context, event Event) error
Query(ctx context.Context, filter EventFilter) ([]Event, error)
QueryWithTotal(ctx context.Context, filter EventFilter) ([]Event, int64, error)
GetByID(ctx context.Context, eventID string) (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) error {
s.mu.Lock()
defer s.mu.Unlock()
event.EventID = generateEventID()
event.CreatedAt = time.Now()
s.events = append(s.events, event)
return nil
}
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
}
// QueryWithTotal 查询事件并返回总数
func (s *MemoryAuditStore) QueryWithTotal(ctx context.Context, filter EventFilter) ([]Event, int64, error) {
s.mu.RLock()
defer s.mu.RUnlock()
var result []Event
total := int64(0)
for _, event := range s.events {
total++
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, total, nil
}
// GetByID 根据事件ID获取单个事件
func (s *MemoryAuditStore) GetByID(ctx context.Context, eventID string) (Event, error) {
s.mu.RLock()
defer s.mu.RUnlock()
for _, event := range s.events {
if event.EventID == eventID {
return event, nil
}
}
return Event{}, fmt.Errorf("event not found")
}
func generateEventID() string {
return time.Now().Format("20060102150405") + "-evt"
}