|
|
|
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 {
|
|
|
|
// 使用安全的GetUserID函数
|
|
|
|
if userID, exists := GetUserID(c); exists {
|
|
|
|
return userID
|
|
|
|
}
|
|
|
|
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))
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
}
|