package collectlogs import ( "encoding/json" "fmt" "strings" "time" "ems.agt/src/framework/constants/common" "ems.agt/src/framework/i18n" "ems.agt/src/framework/utils/ctx" "ems.agt/src/framework/utils/parse" "ems.agt/src/framework/vo/result" "ems.agt/src/modules/system/model" "ems.agt/src/modules/system/service" "github.com/gin-gonic/gin" ) const ( // 业务操作类型-其它 BUSINESS_TYPE_OTHER = "0" // 业务操作类型-新增 BUSINESS_TYPE_INSERT = "1" // 业务操作类型-修改 BUSINESS_TYPE_UPDATE = "2" // 业务操作类型-删除 BUSINESS_TYPE_DELETE = "3" // 业务操作类型-授权 BUSINESS_TYPE_GRANT = "4" // 业务操作类型-导出 BUSINESS_TYPE_EXPORT = "5" // 业务操作类型-导入 BUSINESS_TYPE_IMPORT = "6" // 业务操作类型-强退 BUSINESS_TYPE_FORCE = "7" // 业务操作类型-清空数据 BUSINESS_TYPE_CLEAN = "8" ) const ( // 操作人类别-其它 OPERATOR_TYPE_OTHER = "0" // 操作人类别-后台用户 OPERATOR_TYPE_MANAGE = "1" // 操作人类别-手机端用户 OPERATOR_TYPE_MOBILE = "2" ) // Option 操作日志参数 type Options struct { Title string `json:"title"` // 标题 BusinessType string `json:"businessType"` // 类型,默认常量 BUSINESS_TYPE_OTHER OperatorType string `json:"operatorType"` // 操作人类别,默认常量 OPERATOR_TYPE_OTHER IsSaveRequestData bool `json:"isSaveRequestData"` // 是否保存请求的参数 IsSaveResponseData bool `json:"isSaveResponseData"` // 是否保存响应的参数 } // OptionNew 操作日志参数默认值 // // 标题 "title":"--" // // 类型 "businessType": BUSINESS_TYPE_OTHER // // 注意之后JSON反序列使用:c.ShouldBindBodyWith(¶ms, binding.JSON) func OptionNew(title, businessType string) Options { return Options{ Title: title, BusinessType: businessType, OperatorType: OPERATOR_TYPE_OTHER, IsSaveRequestData: true, IsSaveResponseData: true, } } // 敏感属性字段进行掩码 var maskProperties []string = []string{ "password", "oldPassword", "newPassword", "confirmPassword", } // OperateLog 访问操作日志记录 // // 请在用户身份授权认证校验后使用以便获取登录用户信息 func OperateLog(options Options) gin.HandlerFunc { return func(c *gin.Context) { c.Set("startTime", time.Now()) language := ctx.AcceptLanguage(c) // 函数名 funcName := c.HandlerName() lastDotIndex := strings.LastIndex(funcName, "/") funcName = funcName[lastDotIndex+1:] // 解析ip地址 ipaddr, location := ctx.IPAddrLocation(c) // 获取登录用户信息 loginUser, err := ctx.LoginUser(c) if err != nil { c.JSON(401, result.CodeMsg(401, i18n.TKey(language, err.Error()))) c.Abort() // 停止执行后续的处理函数 return } // 操作日志记录 operLog := model.SysLogOperate{ Title: options.Title, BusinessType: options.BusinessType, OperatorType: options.OperatorType, Method: funcName, OperURL: c.Request.URL.Path, RequestMethod: c.Request.Method, OperIP: ipaddr, OperLocation: location, OperName: loginUser.User.UserName, DeptName: loginUser.User.Dept.DeptName, } if loginUser.User.UserType == "sys" { operLog.OperatorType = OPERATOR_TYPE_MANAGE } // 是否需要保存request,参数和值 if options.IsSaveRequestData { params := ctx.RequestParamsMap(c) 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 } // 调用下一个处理程序 c.Next() // 响应状态 status := c.Writer.Status() if status == 200 { operLog.Status = common.STATUS_YES } else { operLog.Status = common.STATUS_NO } // 是否需要保存response,参数和值 if options.IsSaveResponseData { contentDisposition := c.Writer.Header().Get("Content-Disposition") contentType := c.Writer.Header().Get("Content-Type") content := contentType + contentDisposition msg := fmt.Sprintf(`{"status":"%d","size":"%d","content-type":"%s"}`, status, c.Writer.Size(), content) operLog.OperMsg = msg } // 日志记录时间 duration := time.Since(c.GetTime("startTime")) operLog.CostTime = duration.Milliseconds() operLog.OperTime = time.Now().UnixMilli() // 保存操作记录到数据库 service.NewSysLogOperateImpl.InsertSysLogOperate(operLog) } }