You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

91 lines
2.2 KiB

package middleware
import (
"bytes"
"gofaster/internal/shared/model"
"io"
"strconv"
"strings"
"time"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"gorm.io/gorm"
)
// 从 Gin 上下文中获取用户ID(假设 JWT 中间件已将用户信息存入上下文)
func getUserIdFromContext(c *gin.Context) uint {
if userId, exists := c.Get("userID"); exists {
if uid, ok := userId.(uint); ok {
return uid
}
}
return 0 // 0 表示未登录用户或获取失败
}
// 从请求路径解析操作类型(根据 RESTful 路径映射)
func getActionFromPath(path string) string {
// 移除查询参数和版本前缀(如 /api/v1/users -> /users)
cleanPath := strings.Split(path, "?")[0]
segments := strings.Split(cleanPath, "/")
lastSegment := segments[len(segments)-1]
// 常见 RESTful 操作映射
switch lastSegment {
case "login":
return "用户登录"
case "logout":
return "用户登出"
case "users":
return "用户管理"
case "roles":
return "角色管理"
case "permissions":
return "权限管理"
default:
// 如果是数字ID(如 /users/123),取上一级路径
if _, err := strconv.Atoi(lastSegment); err == nil && len(segments) > 1 {
return getActionFromPath(strings.Join(segments[:len(segments)-1], "/"))
}
return "未知操作"
}
}
func LoggerMiddleware(logger *zap.Logger, db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
path := c.Request.URL.Path
// 记录请求体
var requestBody string
if c.Request.Body != nil {
bodyBytes, _ := io.ReadAll(c.Request.Body)
c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
requestBody = string(bodyBytes)
}
// 处理请求
c.Next()
// 记录日志
latency := time.Since(start).Milliseconds()
actionLog := model.ActionLog{
UserID: getUserIdFromContext(c),
Action: getActionFromPath(path),
IP: c.ClientIP(),
UserAgent: c.Request.UserAgent(),
Path: path,
Method: c.Request.Method,
Request: requestBody,
Status: c.Writer.Status(),
Latency: latency,
}
// 异步保存日志
go func() {
if err := db.Create(&actionLog).Error; err != nil {
logger.Error("保存操作日志失败", zap.Error(err))
}
}()
}
}