136 lines
3.5 KiB
Go
136 lines
3.5 KiB
Go
package midware
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"reflect"
|
|
"runtime"
|
|
"strings"
|
|
"time"
|
|
|
|
"be.ems/lib/core/ctx"
|
|
"be.ems/src/framework/constants"
|
|
"be.ems/src/framework/ip2region"
|
|
"be.ems/src/framework/middleware/collectlogs"
|
|
"be.ems/src/framework/utils/parse"
|
|
"be.ems/src/modules/system/model"
|
|
"be.ems/src/modules/system/service"
|
|
)
|
|
|
|
// 敏感属性字段进行掩码
|
|
var maskProperties []string = []string{
|
|
"password",
|
|
"oldPassword",
|
|
"newPassword",
|
|
"confirmPassword",
|
|
}
|
|
|
|
// LogOperate 操作日志搜集
|
|
func LogOperate(options collectlogs.Options) func(http.Handler) http.Handler {
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
startTime := time.Now()
|
|
|
|
// 只对前端发送的数据进行记录
|
|
appCodeStr := r.Header.Get("X-App-Code")
|
|
if appCodeStr == "" {
|
|
next.ServeHTTP(w, r)
|
|
return
|
|
}
|
|
|
|
// 函数名
|
|
funcName := runtime.FuncForPC(reflect.ValueOf(next).Pointer()).Name()
|
|
lastDotIndex := strings.LastIndex(funcName, "/")
|
|
funcName = funcName[lastDotIndex+1:]
|
|
|
|
// 用户名
|
|
username := ctx.LoginUserToUserName(r)
|
|
|
|
// 解析ip地址
|
|
ip := strings.Split(r.RemoteAddr, ":")[0]
|
|
ipaddr := ip2region.ClientIP(ip)
|
|
location := "-" //ip2region.RealAddressByIp(ipaddr)
|
|
// 操作日志记录
|
|
operLog := model.SysLogOperate{
|
|
Title: options.Title,
|
|
BusinessType: options.BusinessType,
|
|
OperaMethod: funcName,
|
|
OperaUrl: r.RequestURI,
|
|
OperaUrlMethod: r.Method,
|
|
OperaIp: ipaddr,
|
|
OperaLocation: location,
|
|
OperaBy: username,
|
|
}
|
|
|
|
// 是否需要保存request,参数和值
|
|
if options.IsSaveRequestData && (r.Method == "POST" || r.Method == "PUT") {
|
|
// 读取请求体内容
|
|
body, err := io.ReadAll(r.Body)
|
|
if err != nil {
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
// 解析json内参数
|
|
var bodyArgs map[string]any
|
|
_ = json.Unmarshal(bytes.Clone(body), &bodyArgs)
|
|
// 将请求体内容存储在临时缓冲区中
|
|
buffer := bytes.NewBuffer(body)
|
|
r.Body = io.NopCloser(buffer)
|
|
|
|
params := bodyArgs
|
|
for k, v := range params {
|
|
// 敏感属性字段进行掩码
|
|
for _, s := range maskProperties {
|
|
if s == k {
|
|
params[k] = parse.SafeContent(v.(string))
|
|
break
|
|
}
|
|
}
|
|
}
|
|
jsonStr, _ := json.Marshal(params)
|
|
paramsStr := string(jsonStr)
|
|
if len(paramsStr) > 2000 {
|
|
paramsStr = paramsStr[:2000]
|
|
}
|
|
operLog.OperaParam = paramsStr
|
|
}
|
|
|
|
next.ServeHTTP(w, r)
|
|
|
|
// 响应内容长度和状态码作为结果
|
|
str := strings.TrimSuffix(fmt.Sprintf("%v", w), "}")
|
|
strArr := strings.Split(str, " ")
|
|
size := strArr[1]
|
|
status := strArr[2]
|
|
|
|
// 响应状态
|
|
if status == "200" || status == "204" {
|
|
operLog.StatusFlag = constants.STATUS_YES
|
|
} else {
|
|
operLog.StatusFlag = constants.STATUS_NO
|
|
}
|
|
|
|
// 是否需要保存response,参数和值
|
|
if options.IsSaveResponseData {
|
|
contentDisposition := w.Header().Get("Content-Disposition")
|
|
contentType := w.Header().Get("Content-Type")
|
|
content := contentType + contentDisposition
|
|
msg := fmt.Sprintf(`{"status":"%s","size":"%s","content-type":"%s"}`, status, size, content)
|
|
operLog.OperaMsg = msg
|
|
}
|
|
|
|
// 日志记录时间
|
|
duration := time.Since(startTime)
|
|
operLog.CostTime = duration.Milliseconds()
|
|
operLog.OperaTime = time.Now().UnixMilli()
|
|
|
|
// 保存操作记录到数据库
|
|
service.NewSysLogOperate.Insert(operLog)
|
|
|
|
})
|
|
}
|
|
}
|