144 lines
3.8 KiB
Go
144 lines
3.8 KiB
Go
package midware
|
||
|
||
import (
|
||
"bytes"
|
||
"encoding/json"
|
||
"fmt"
|
||
"io"
|
||
"net/http"
|
||
"reflect"
|
||
"runtime"
|
||
"strings"
|
||
"time"
|
||
|
||
"ems.agt/lib/core/utils/parse"
|
||
"ems.agt/lib/dborm"
|
||
"ems.agt/src/framework/constants/common"
|
||
"ems.agt/src/framework/middleware/collectlogs"
|
||
"ems.agt/src/framework/utils/ip2region"
|
||
"ems.agt/src/modules/system/model"
|
||
"ems.agt/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 := "-"
|
||
accessToken := r.Header.Get("AccessToken")
|
||
if accessToken != "" {
|
||
// 验证令牌 == 这里直接查数据库session
|
||
se, _ := dborm.XormUpdateSessionShakeTime(accessToken)
|
||
username = se.AccountId
|
||
}
|
||
|
||
// 解析ip地址
|
||
ip := strings.Split(r.RemoteAddr, ":")[0]
|
||
ipaddr := ip2region.ClientIP(ip)
|
||
location := ip2region.RealAddressByIp(ipaddr)
|
||
// 操作日志记录
|
||
operLog := model.SysLogOperate{
|
||
Title: options.Title,
|
||
BusinessType: options.BusinessType,
|
||
OperatorType: collectlogs.OPERATOR_TYPE_MANAGE,
|
||
Method: funcName,
|
||
OperURL: r.RequestURI,
|
||
RequestMethod: r.Method,
|
||
OperIP: ipaddr,
|
||
OperLocation: location,
|
||
OperName: username,
|
||
DeptName: "",
|
||
}
|
||
|
||
// 是否需要保存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.OperParam = 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.Status = common.STATUS_YES
|
||
} else {
|
||
operLog.Status = common.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.OperMsg = msg
|
||
}
|
||
|
||
// 日志记录时间
|
||
duration := time.Since(startTime)
|
||
operLog.CostTime = duration.Milliseconds()
|
||
operLog.OperTime = time.Now().UnixMilli()
|
||
|
||
// 保存操作记录到数据库
|
||
service.NewSysLogOperateImpl.InsertSysLogOperate(operLog)
|
||
|
||
})
|
||
}
|
||
}
|