init
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
"github.com/goravel/framework/facades"
|
||||
|
||||
"goravel/app/http/helpers"
|
||||
"goravel/app/models"
|
||||
"goravel/app/services"
|
||||
"goravel/app/utils"
|
||||
"goravel/app/utils/logger"
|
||||
"goravel/app/utils/traceid"
|
||||
)
|
||||
|
||||
// OperationLog 操作日志中间件
|
||||
func OperationLog() http.Middleware {
|
||||
return func(ctx http.Context) {
|
||||
systemLogService := services.NewSystemLogService()
|
||||
startTime := time.Now()
|
||||
|
||||
// 获取请求信息
|
||||
method := ctx.Request().Method()
|
||||
path := ctx.Request().Path()
|
||||
ip := ctx.Request().Ip()
|
||||
userAgent := ctx.Request().Header("User-Agent", "")
|
||||
|
||||
// 获取请求参数(排除敏感信息)
|
||||
var requestBody string
|
||||
if method == "POST" || method == "PUT" || method == "PATCH" {
|
||||
// 获取所有输入参数
|
||||
inputs := make(map[string]any)
|
||||
// 记录所有非敏感参数
|
||||
allInputs := ctx.Request().All()
|
||||
for key, value := range allInputs {
|
||||
// 使用工具函数检查是否是敏感字段
|
||||
if utils.IsSensitiveField(key) {
|
||||
inputs[key] = "***"
|
||||
} else {
|
||||
inputs[key] = value
|
||||
}
|
||||
}
|
||||
if data, err := json.Marshal(inputs); err == nil {
|
||||
requestBody = string(data)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取管理员ID(从JWT中间件设置的context中获取)
|
||||
var adminID uint
|
||||
if admin, err := helpers.GetAdminFromContext(ctx); err == nil {
|
||||
adminID = admin.ID
|
||||
}
|
||||
|
||||
// 继续处理请求
|
||||
ctx.Request().Next()
|
||||
|
||||
// 计算耗时
|
||||
duration := int(time.Since(startTime).Milliseconds())
|
||||
|
||||
// 只记录新增、修改、删除操作(POST、PUT、PATCH、DELETE),排除 GET 请求
|
||||
// 同时排除登录和info接口,以及分片上传的进度查询(GET请求)
|
||||
// 排除代码生成器相关操作
|
||||
// 对于分片上传,只记录 merge 操作(最终完成上传),排除 init 和 upload 操作
|
||||
if (method == "POST" || method == "PUT" || method == "PATCH" || method == "DELETE") &&
|
||||
path != "/api/admin/login" && path != "/api/admin/info" &&
|
||||
!strings.HasPrefix(path, "/api/admin/code-generator/") {
|
||||
|
||||
// 排除分片上传的中间操作(init 和 upload),只记录 merge(最终完成上传)
|
||||
if path == "/api/admin/attachments/chunk" {
|
||||
action := ctx.Request().Input("action", "")
|
||||
if action == "" {
|
||||
action = ctx.Request().Query("action", "")
|
||||
}
|
||||
// 只记录 merge 操作,排除 init、upload 和 progress
|
||||
if action != "merge" {
|
||||
return
|
||||
}
|
||||
}
|
||||
// 在请求处理后再获取一次管理员ID(确保JWT中间件已执行)
|
||||
// 如果之前没有获取到,再次尝试从context获取
|
||||
if adminID == 0 {
|
||||
if admin, err := helpers.GetAdminFromContext(ctx); err == nil {
|
||||
adminID = admin.ID
|
||||
}
|
||||
}
|
||||
|
||||
// 默认状态为成功
|
||||
status := uint8(1)
|
||||
var errorMsg string
|
||||
|
||||
// 在goroutine之前保存所有需要的数据,避免context问题
|
||||
savedAdminID := adminID
|
||||
savedMethod := method
|
||||
savedPath := path
|
||||
savedIP := ip
|
||||
savedUserAgent := userAgent
|
||||
savedRequestBody := requestBody
|
||||
savedDuration := duration
|
||||
|
||||
// 提前获取 traceCtx,用于日志记录
|
||||
traceCtx := traceid.DeriveContextFromHTTP(ctx)
|
||||
|
||||
// 生成操作标题(只使用权限标识)
|
||||
title := utils.GetOperationTitleFromContext(ctx)
|
||||
if title == "operation.unknown" {
|
||||
// 如果无法生成标题,记录调试日志
|
||||
logger.ErrorfContext(traceCtx, "Failed to generate operation title, method: %s, path: %s", savedMethod, savedPath)
|
||||
}
|
||||
|
||||
operationLog := models.OperationLog{
|
||||
AdminID: savedAdminID,
|
||||
Method: savedMethod,
|
||||
Path: savedPath,
|
||||
Title: title,
|
||||
IP: savedIP,
|
||||
UserAgent: savedUserAgent,
|
||||
Request: savedRequestBody,
|
||||
Status: status,
|
||||
ErrorMsg: errorMsg,
|
||||
Duration: savedDuration,
|
||||
}
|
||||
|
||||
// 异步记录日志,避免影响响应速度
|
||||
go func(ctx context.Context) {
|
||||
if err := facades.Orm().Query().Create(&operationLog); err != nil {
|
||||
_ = systemLogService.Record(ctx, "error", "operation-log", "failed to persist operation log", map[string]any{
|
||||
"error": err.Error(),
|
||||
"path": savedPath,
|
||||
})
|
||||
logger.ErrorfContext(ctx, "Failed to create operation log: %v", err)
|
||||
}
|
||||
}(traceCtx)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user