From 0633f38ca049f1c8a608e12cea65b4b81e4d0695 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Fri, 20 Oct 2023 18:34:18 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0mml=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E5=92=8C=E6=93=8D=E4=BD=9C=E6=97=A5=E5=BF=97=E6=94=B6=E9=9B=86?= =?UTF-8?q?=E4=B8=AD=E9=97=B4=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/midware/mml_log.go | 68 +++++++++++++++++++ lib/midware/operate_log.go | 136 +++++++++++++++++++++++++++++++++++++ lib/routes/routes.go | 27 ++++---- 3 files changed, 218 insertions(+), 13 deletions(-) create mode 100644 lib/midware/mml_log.go create mode 100644 lib/midware/operate_log.go diff --git a/lib/midware/mml_log.go b/lib/midware/mml_log.go new file mode 100644 index 00000000..6a41713b --- /dev/null +++ b/lib/midware/mml_log.go @@ -0,0 +1,68 @@ +package midware + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + "time" + + "ems.agt/lib/core/datasource" + "ems.agt/lib/core/utils/ctx" + "ems.agt/lib/core/utils/date" + "ems.agt/lib/dborm" + "ems.agt/lib/log" +) + +// LogMML mml操作日志搜集 +func LogMML(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // 读取请求体内容 + 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) + + next.ServeHTTP(w, r) + + // 收尾存入数据库的参数 + mmlCmd := bodyArgs["mml"].([]any)[0] + ipAddr := strings.Split(r.RemoteAddr, ":")[0] + neType := ctx.Param(r, "elementTypeValue") + neId := ctx.GetQuery(r, "ne_id") + timeStr := date.ParseDateToStr(time.Now(), date.YYYY_MM_DD_HH_MM_SS) + + // 响应内容长度和状态码作为结果 + str := strings.TrimSuffix(fmt.Sprintf("%v", w), "}") + strArr := strings.Split(str, " ") + size := strArr[1] + status := strArr[2] + contentType := w.Header().Get("Content-Type") + resultStr := fmt.Sprintf(`{"status":"%s","size":"%s","content-type":"%s"}`, status, size, contentType) + + // 用户名 + username := "-" + accessToken := r.Header.Get("AccessToken") + if accessToken != "" { + // 验证令牌 == 这里直接查数据库session + se, _ := dborm.XormUpdateSessionShakeTime(accessToken) + username = se.AccountId + } + + // 执行插入 + sql := "insert into mml_log (user,ip,ne_type,ne_id,mml,result,log_time)values(?,?,?,?,?,?,?)" + _, sqlerr := datasource.ExecDB("", sql, []any{username, ipAddr, neType, neId, mmlCmd, resultStr, timeStr}) + if sqlerr != nil { + log.Errorf("insert row : %v", err.Error()) + } + }) +} diff --git a/lib/midware/operate_log.go b/lib/midware/operate_log.go new file mode 100644 index 00000000..440faa62 --- /dev/null +++ b/lib/midware/operate_log.go @@ -0,0 +1,136 @@ +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() + + // 函数名 + 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" { + 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) + + }) + } +} diff --git a/lib/routes/routes.go b/lib/routes/routes.go index 0a971566..063377b7 100644 --- a/lib/routes/routes.go +++ b/lib/routes/routes.go @@ -30,6 +30,7 @@ import ( "ems.agt/features/ue" "ems.agt/lib/midware" "ems.agt/lib/services" + "ems.agt/src/framework/middleware/collectlogs" "github.com/gorilla/mux" ) @@ -169,12 +170,12 @@ func init() { //ne service action handle Register("POST", cm.UriNeInstance, cm.PostNeInstanceAction, nil) // Post MML command to NF - Register("POST", mml.UriMML, mml.PostMMLToNF, nil) + Register("POST", mml.UriMML, mml.PostMMLToNF, midware.LogMML) Register("POST", mml.UriMMLDiscard, mml.PostMMLToNF, nil) - Register("POST", mml.UriOmMmlExt, mml.PostMMLToOMC, nil) + Register("POST", mml.UriOmMmlExt, mml.PostMMLToOMC, midware.LogMML) - Register("POST", mml.CustomUriMML, mml.PostMMLToNF, nil) - Register("POST", mml.CustomUriOmMmlExt, mml.PostMMLToOMC, nil) + Register("POST", mml.CustomUriMML, mml.PostMMLToNF, midware.LogMML) + Register("POST", mml.CustomUriOmMmlExt, mml.PostMMLToOMC, midware.LogMML) // Northbound Get NRM Register("GET", nbi.GetNRMUri, nbi.NBIGetNRMFromNF, nil) @@ -219,9 +220,9 @@ func init() { Register("POST", cm.CustomUriLicenseExt, cm.UploadLicenseFileData, nil) // Trace management - Register("POST", trace.UriTraceTask, trace.PostTraceTaskToNF, nil) - Register("PUT", trace.UriTraceTask, trace.PutTraceTaskToNF, nil) - Register("DELETE", trace.UriTraceTask, trace.DeleteTraceTaskToNF, nil) + Register("POST", trace.UriTraceTask, trace.PostTraceTaskToNF, midware.LogOperate(collectlogs.OptionNew("跟踪任务", collectlogs.BUSINESS_TYPE_INSERT))) + Register("PUT", trace.UriTraceTask, trace.PutTraceTaskToNF, midware.LogOperate(collectlogs.OptionNew("跟踪任务", collectlogs.BUSINESS_TYPE_UPDATE))) + Register("DELETE", trace.UriTraceTask, trace.DeleteTraceTaskToNF, midware.LogOperate(collectlogs.OptionNew("跟踪任务", collectlogs.BUSINESS_TYPE_DELETE))) Register("GET", trace.UriTraceDecMsg, trace.ParseRawMsg2Html, nil) Register("POST", trace.CustomUriTraceTask, trace.PostTraceTaskToNF, nil) @@ -229,14 +230,14 @@ func init() { Register("DELETE", trace.CustomUriTraceTask, trace.DeleteTraceTaskToNF, nil) // 网元发送执行 pcap抓包 - Register("POST", trace.UriTcpdumpTask, trace.TcpdumpNeTask, midware.Authorize(nil)) - Register("POST", trace.CustomUriTcpdumpTask, trace.TcpdumpNeTask, midware.Authorize(nil)) + Register("POST", trace.UriTcpdumpTask, trace.TcpdumpNeTask, midware.LogOperate(collectlogs.OptionNew("抓包任务", collectlogs.BUSINESS_TYPE_INSERT))) + Register("POST", trace.CustomUriTcpdumpTask, trace.TcpdumpNeTask, midware.LogOperate(collectlogs.OptionNew("抓包任务", collectlogs.BUSINESS_TYPE_INSERT))) // 网元发送执行 抓包下载pcap文件 - Register("POST", trace.UriTcpdumpPcapDownload, trace.TcpdumpPcapDownload, midware.Authorize(nil)) - Register("POST", trace.CustomUriTcpdumpPcapDownload, trace.TcpdumpPcapDownload, midware.Authorize(nil)) + Register("POST", trace.UriTcpdumpPcapDownload, trace.TcpdumpPcapDownload, midware.LogOperate(collectlogs.OptionNew("抓包任务", collectlogs.BUSINESS_TYPE_EXPORT))) + Register("POST", trace.CustomUriTcpdumpPcapDownload, trace.TcpdumpPcapDownload, midware.LogOperate(collectlogs.OptionNew("抓包任务", collectlogs.BUSINESS_TYPE_EXPORT))) // 网元发送执行UPF pcap抓包 - Register("POST", trace.UriTcpdumpNeUPFTask, trace.TcpdumpNeUPFTask, nil) - Register("POST", trace.CustomUriTcpdumpNeUPFTask, trace.TcpdumpNeUPFTask, nil) + Register("POST", trace.UriTcpdumpNeUPFTask, trace.TcpdumpNeUPFTask, midware.LogOperate(collectlogs.OptionNew("抓包任务", collectlogs.BUSINESS_TYPE_INSERT))) + Register("POST", trace.CustomUriTcpdumpNeUPFTask, trace.TcpdumpNeUPFTask, midware.LogOperate(collectlogs.OptionNew("抓包任务", collectlogs.BUSINESS_TYPE_INSERT))) // file management Register("POST", file.UriFile, file.UploadFile, nil)