package handler import ( "encoding/json" "log/slog" "net/http" "strconv" "silk-server-go/internal/middleware" "silk-server-go/internal/model" "github.com/gin-gonic/gin" "gorm.io/gorm" ) // RegisterAuditRoutes 注册审计日志路由 func RegisterAuditRoutes(rg *gin.RouterGroup, db *gorm.DB) { perm := middleware.RequirePermission(db, "audit:read") rg.GET("/audit-logs", perm, listAuditLogs(db)) rg.POST("/audit-logs", perm, createAuditLog(db)) } // listAuditLogs 审计日志列表(query: limit,默认100,上限500) func listAuditLogs(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { limit := 100 if l := c.Query("limit"); l != "" { if n, err := strconv.Atoi(l); err == nil && n > 0 { limit = n } } if limit > 500 { limit = 500 } var logs []model.AuditLog db.Order("created_at DESC").Limit(limit).Find(&logs) c.JSON(http.StatusOK, logs) } } // createAuditLog 手动写入审计日志,自动补充 userId/username/IP/UA func createAuditLog(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { var body struct { Action string `json:"action"` Resource *string `json:"resource"` TargetID *string `json:"targetId"` Description *string `json:"description"` Metadata json.RawMessage `json:"metadata"` } if err := c.ShouldBindJSON(&body); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if body.Action == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "action 不能为空"}) return } // 从 context 获取当前用户信息 var userID, username *string if user, ok := c.Get("user"); ok { if userMap, ok := user.(map[string]interface{}); ok { if sub, ok := userMap["sub"].(string); ok { s := sub userID = &s } if uname, ok := userMap["username"].(string); ok { s := uname username = &s } } } ip := c.ClientIP() ua := c.GetHeader("User-Agent") log := model.AuditLog{ UserID: userID, Username: username, Action: body.Action, Resource: body.Resource, TargetID: body.TargetID, Description: body.Description, IPAddress: &ip, UserAgent: &ua, Metadata: body.Metadata, } if err := db.Create(&log).Error; err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "写入审计日志失败"}) return } c.JSON(http.StatusCreated, log) } } // recordAudit 记录审计日志(供其他 handler 调用) func recordAudit(db *gorm.DB, log *model.AuditLog) { if log == nil || log.Action == "" { return } if err := db.Create(log).Error; err != nil { slog.Warn("记录审计日志失败", "error", err) } }