Files
logs/internal/logic/audit/middleware.go
2026-06-26 12:51:50 +08:00

67 lines
1.8 KiB
Go

package audit
import (
"bytes"
"io"
"strings"
"github.com/gin-gonic/gin"
)
type ActorResolver func(*gin.Context) (id string, name string)
func Middleware(sourceService string, resolveActor ActorResolver) gin.HandlerFunc {
sourceService = strings.TrimSpace(sourceService)
return func(ctx *gin.Context) {
if ctx.Request.Method == "GET" || ctx.Request.Method == "HEAD" || ctx.Request.Method == "OPTIONS" {
ctx.Next()
return
}
var body []byte
if ctx.Request.Body != nil {
body, _ = io.ReadAll(ctx.Request.Body)
ctx.Request.Body = io.NopCloser(bytes.NewBuffer(body))
}
ctx.Next()
actorID, actorName := "", ""
if resolveActor != nil {
actorID, actorName = resolveActor(ctx)
}
if actorID == "" {
actorID = firstNonEmpty(ctx.GetHeader("X-User-Id"), ctx.GetHeader("X-Actor-Id"), "unknown")
}
if actorName == "" {
actorName = firstNonEmpty(ctx.GetHeader("X-User-Name"), ctx.GetHeader("X-Actor-Name"))
}
result := "success"
if len(ctx.Errors) > 0 || ctx.Writer.Status() >= 400 {
result = "failed"
}
_, _ = SaveRecord(Record{
TraceID: firstNonEmpty(ctx.GetHeader("X-Trace-Id"), ctx.GetHeader("Request-Id")),
SourceService: sourceService,
ActorID: actorID,
ActorName: actorName,
Action: ctx.Request.Method + " " + ctx.FullPath(),
ObjectType: routeObjectType(ctx.FullPath()),
ObjectID: firstNonEmpty(ctx.Param("id"), ctx.Query("id"), ctx.FullPath()),
RequestMethod: ctx.Request.Method,
RequestPath: ctx.FullPath(),
ClientIP: ctx.ClientIP(),
AfterJSON: string(body),
Result: result,
})
}
}
func routeObjectType(path string) string {
path = strings.Trim(path, "/")
if path == "" {
return "unknown"
}
parts := strings.Split(path, "/")
return parts[len(parts)-1]
}