diff --git a/.gitignore b/.gitignore index c3c377d..252eeb5 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ # Local History for Visual Studio Code .history/ +.idea/ # Run temp file and dir crontask/log/ diff --git a/features/trace/tcpdump.go b/features/trace/tcpdump.go index 9aebd1d..5f13fca 100644 --- a/features/trace/tcpdump.go +++ b/features/trace/tcpdump.go @@ -64,7 +64,7 @@ func TcpdumpNeTask(w http.ResponseWriter, r *http.Request) { filePcapName := fmt.Sprintf("tmp_%s_%s_%d.pcap", body.NeType, body.NeId, time.Now().UnixMilli()) fileLogName := fmt.Sprintf("tmp_%s_%s_%d.log", body.NeType, body.NeId, time.Now().UnixMilli()) writeLog := fmt.Sprintf(" >> %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件,放置弹出code 127 - cmdStr := fmt.Sprintf("cd /tmp \n%stimeout %d tcpdump -i any %s -s0 -w %s", cmd.SudoHandleCmd(), body.Timeout, body.Cmd, filePcapName) + cmdStr := fmt.Sprintf("cd /tmp \nsudo timeout %d tcpdump -i any %s -s0 -w %s", body.Timeout, body.Cmd, filePcapName) usernameNe := conf.Get("ne.user").(string) // 网元统一用户 sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip) msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr+writeLog) diff --git a/features/udm_user/api_udm_user.go b/features/udm_user/api_udm_user.go index 29e4f5a..c441085 100644 --- a/features/udm_user/api_udm_user.go +++ b/features/udm_user/api_udm_user.go @@ -20,6 +20,7 @@ import ( "ems.agt/lib/midware" "ems.agt/lib/services" "ems.agt/restagent/config" + "ems.agt/src/framework/middleware/collectlogs" ) // UDM 用户信息接口添加到路由 @@ -31,7 +32,7 @@ func Routers() []services.RouterItem { } rs := [...]services.RouterItem{ - // UDM签约用户 + // UDM鉴权用户 { Method: "GET", Pattern: "/auths", @@ -42,7 +43,7 @@ func Routers() []services.RouterItem { Method: "POST", Pattern: "/authSave/{neId}", Handler: apis.UdmAuthUserSave, - Middleware: midware.Authorize(nil), + Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Authentication User", collectlogs.BUSINESS_TYPE_INSERT)), }, { Method: "GET", @@ -54,43 +55,43 @@ func Routers() []services.RouterItem { Method: "POST", Pattern: "/auth/{neId}", Handler: apis.UdmAuthUserAdd, - Middleware: midware.Authorize(nil), + Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Authentication User", collectlogs.BUSINESS_TYPE_INSERT)), }, { Method: "POST", Pattern: "/auth/{neId}/{num}", Handler: apis.UdmAuthUserAdds, - Middleware: midware.Authorize(nil), + Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Authentication User", collectlogs.BUSINESS_TYPE_INSERT)), }, { Method: "PUT", Pattern: "/auth/{neId}", Handler: apis.UdmAuthUserEdit, - Middleware: midware.Authorize(nil), + Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Authentication User", collectlogs.BUSINESS_TYPE_UPDATE)), }, { Method: "DELETE", Pattern: "/auth/{neId}/{imsi}", Handler: apis.UdmAuthUserRemove, - Middleware: midware.Authorize(nil), + Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Authentication User", collectlogs.BUSINESS_TYPE_DELETE)), }, { Method: "DELETE", Pattern: "/auth/{neId}/{imsi}/{num}", Handler: apis.UdmAuthUserRemoves, - Middleware: midware.Authorize(nil), + Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Authentication User", collectlogs.BUSINESS_TYPE_DELETE)), }, { Method: "POST", Pattern: "/authExport", Handler: apis.UdmAuthUserExport, - Middleware: midware.Authorize(nil), + Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Authentication User", collectlogs.BUSINESS_TYPE_EXPORT)), }, { Method: "POST", Pattern: "/authImport/{neId}", Handler: apis.UdmAuthUserImport, - Middleware: midware.Authorize(nil), + Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Authentication User", collectlogs.BUSINESS_TYPE_IMPORT)), }, // UDM签约用户 { @@ -103,7 +104,7 @@ func Routers() []services.RouterItem { Method: "POST", Pattern: "/subSave/{neId}", Handler: apis.UdmSubUserSave, - Middleware: midware.Authorize(nil), + Middleware: midware.LogOperate(collectlogs.OptionNew("UDM contracted users", collectlogs.BUSINESS_TYPE_INSERT)), }, { Method: "GET", @@ -115,55 +116,55 @@ func Routers() []services.RouterItem { Method: "POST", Pattern: "/sub/{neId}", Handler: apis.UdmSubUserAdd, - Middleware: midware.Authorize(nil), + Middleware: midware.LogOperate(collectlogs.OptionNew("UDM contracted users", collectlogs.BUSINESS_TYPE_INSERT)), }, { Method: "POST", Pattern: "/sub/{neId}/{num}", Handler: apis.UdmSubUserAdds, - Middleware: midware.Authorize(nil), + Middleware: midware.LogOperate(collectlogs.OptionNew("UDM contracted users", collectlogs.BUSINESS_TYPE_INSERT)), }, { Method: "PUT", Pattern: "/sub/{neId}", Handler: apis.UdmSubUserEdit, - Middleware: midware.Authorize(nil), + Middleware: midware.LogOperate(collectlogs.OptionNew("UDM contracted users", collectlogs.BUSINESS_TYPE_UPDATE)), }, { Method: "PUT", Pattern: "/sub4gIP/{neId}", Handler: apis.UdmSubUser4GIP, - Middleware: midware.Authorize(nil), + Middleware: midware.LogOperate(collectlogs.OptionNew("UDM contracted users", collectlogs.BUSINESS_TYPE_UPDATE)), }, { Method: "PUT", Pattern: "/subSmData/{neId}", Handler: apis.UdmSubUserSmData, - Middleware: midware.Authorize(nil), + Middleware: midware.LogOperate(collectlogs.OptionNew("UDM contracted users", collectlogs.BUSINESS_TYPE_UPDATE)), }, { Method: "DELETE", Pattern: "/sub/{neId}/{imsi}", Handler: apis.UdmSubUserRemove, - Middleware: midware.Authorize(nil), + Middleware: midware.LogOperate(collectlogs.OptionNew("UDM contracted users", collectlogs.BUSINESS_TYPE_DELETE)), }, { Method: "DELETE", Pattern: "/sub/{neId}/{imsi}/{num}", Handler: apis.UdmSubUserRemoves, - Middleware: midware.Authorize(nil), + Middleware: midware.LogOperate(collectlogs.OptionNew("UDM contracted users", collectlogs.BUSINESS_TYPE_DELETE)), }, { Method: "POST", Pattern: "/subExport", Handler: apis.UdmSubUserExport, - Middleware: midware.Authorize(nil), + Middleware: midware.LogOperate(collectlogs.OptionNew("UDM contracted users", collectlogs.BUSINESS_TYPE_EXPORT)), }, { Method: "POST", Pattern: "/subImport/{neId}", Handler: apis.UdmSubUserImport, - Middleware: midware.Authorize(nil), + Middleware: midware.LogOperate(collectlogs.OptionNew("UDM contracted users", collectlogs.BUSINESS_TYPE_IMPORT)), }, // 添加更多的 Router 对象... } diff --git a/lib/midware/mml_log.go b/lib/midware/mml_log.go new file mode 100644 index 0000000..6a41713 --- /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 0000000..440faa6 --- /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 0a97156..f55ade6 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) @@ -218,25 +219,25 @@ func init() { Register("POST", cm.CustomUriLicense, cm.UploadLicenseFileData, nil) 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) + // Trace management 跟踪任务 + Register("POST", trace.UriTraceTask, trace.PostTraceTaskToNF, midware.LogOperate(collectlogs.OptionNew("Trace Task", collectlogs.BUSINESS_TYPE_INSERT))) + Register("PUT", trace.UriTraceTask, trace.PutTraceTaskToNF, midware.LogOperate(collectlogs.OptionNew("Trace Task", collectlogs.BUSINESS_TYPE_UPDATE))) + Register("DELETE", trace.UriTraceTask, trace.DeleteTraceTaskToNF, midware.LogOperate(collectlogs.OptionNew("Trace Task", collectlogs.BUSINESS_TYPE_DELETE))) Register("GET", trace.UriTraceDecMsg, trace.ParseRawMsg2Html, nil) Register("POST", trace.CustomUriTraceTask, trace.PostTraceTaskToNF, nil) Register("PUT", trace.CustomUriTraceTask, trace.PutTraceTaskToNF, nil) 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)) + // 网元发送执行 pcap抓包任务 + Register("POST", trace.UriTcpdumpTask, trace.TcpdumpNeTask, midware.LogOperate(collectlogs.OptionNew("Packet capturing task", collectlogs.BUSINESS_TYPE_INSERT))) + Register("POST", trace.CustomUriTcpdumpTask, trace.TcpdumpNeTask, midware.LogOperate(collectlogs.OptionNew("Packet capturing task", 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("Packet capturing task", collectlogs.BUSINESS_TYPE_EXPORT))) + Register("POST", trace.CustomUriTcpdumpPcapDownload, trace.TcpdumpPcapDownload, midware.LogOperate(collectlogs.OptionNew("Packet capturing task", 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("Packet capturing task", collectlogs.BUSINESS_TYPE_INSERT))) + Register("POST", trace.CustomUriTcpdumpNeUPFTask, trace.TcpdumpNeUPFTask, midware.LogOperate(collectlogs.OptionNew("Packet capturing task", collectlogs.BUSINESS_TYPE_INSERT))) // file management Register("POST", file.UriFile, file.UploadFile, nil) diff --git a/restagent/etc/restconf-t.yaml b/restagent/etc/restconf-t.yaml index 2a8acc4..6ea8d46 100644 --- a/restagent/etc/restconf-t.yaml +++ b/restagent/etc/restconf-t.yaml @@ -12,10 +12,10 @@ logger: # ip: 0.0.0.0 or ::0, support IPv4/v6 rest: - ipv4: 0.0.0.0 - ipv6: fe80::f6bb:7d5f:bcb2:763b%7 + ipv6: port: 3030 - ipv4: 0.0.0.0 - ipv6: fe80::f6bb:7d5f:bcb2:763b%7 + ipv6: port: 6060 database: @@ -33,13 +33,13 @@ redis: # OMC系统使用库 default: port: 6379 # Redis port - host: "192.168.0.229" # Redis host + host: "192.168.2.166" # Redis host password: "" db: 10 # Redis db_num # UDM网元用户库 udmuser: port: 6379 # Redis port - host: "192.168.0.229" + host: "192.168.2.166" password: "" db: 0 # Redis db_num # 多个数据源时可以用这个指定默认的数据源 diff --git a/src/framework/errorcatch/errorcatch.go b/src/framework/errorcatch/errorcatch.go index baa4258..c4d8fec 100644 --- a/src/framework/errorcatch/errorcatch.go +++ b/src/framework/errorcatch/errorcatch.go @@ -16,7 +16,7 @@ func ErrorCatch() gin.HandlerFunc { defer func() { // 在这里处理 Panic 异常,例如记录日志或返回错误信息给客户端 if err := recover(); err != nil { - logger.Errorf("发生了 Panic 异常: %v", err) + logger.Errorf("Panic 异常: %s => %v", c.Request.URL, err) // 返回错误响应给客户端 if config.Env() == "prod" { diff --git a/src/lib_features/account/account.go b/src/lib_features/account/account.go index 9e4e5ea..352829c 100644 --- a/src/lib_features/account/account.go +++ b/src/lib_features/account/account.go @@ -12,18 +12,19 @@ import ( // SessionToken 设置登录会话-兼容旧登录方式 func SessionToken(username, sourceAddr string) bool { - token, _ := redis.Get("", "session_token") - if token != "" { - se, err := dborm.XormUpdateSessionShakeTime(token) - if se.AccountId != username || err != nil { - // 过期时间单位秒 配置1800是半小时 - expireTime := time.Duration(int64(libConfig.GetExpiresFromConfig())) * time.Second - redis.SetByExpire("", "session_token", token, expireTime) - return true - } - } - - token = oauth.GenRandToken("omc") // Generate new token to session ID + // token, _ := redis.Get("", "session_token") + // if token != "" { + // se, err := dborm.XormUpdateSessionShakeTime(token) + // if se.AccountId != username || err != nil { + // // 过期时间单位秒 配置1800是半小时 + // expireTime := time.Duration(int64(libConfig.GetExpiresFromConfig())) * time.Second + // redis.SetByExpire("", "session_token", token, expireTime) + // return true + // } + // } + // 不管原先的登录情况,直接插入写入覆盖redis中session + // + token := oauth.GenRandToken("omc") // Generate new token to session ID affected, err := dborm.XormInsertSession(username, sourceAddr, token, libConfig.GetExpiresFromConfig(), libConfig.GetYamlConfig().Auth.Session) if err != nil { logger.Errorf("SessionToken XormInsertSession err %v", err) diff --git a/src/lib_features/session/session.go b/src/lib_features/session/session.go index e7c4a11..fbb4541 100644 --- a/src/lib_features/session/session.go +++ b/src/lib_features/session/session.go @@ -1,8 +1,10 @@ package session import ( - "ems.agt/src/framework/redis" + "time" + libConfig "ems.agt/restagent/config" + "ems.agt/src/framework/redis" "github.com/gin-gonic/gin" ) @@ -11,7 +13,10 @@ func SessionHeader() gin.HandlerFunc { return func(c *gin.Context) { // 读取登录生成的会话token token, err := redis.Get("", "session_token") - if err == nil { + if token != "" || err == nil { + // 过期时间单位秒 配置1800是半小时 + expireTime := time.Duration(int64(libConfig.GetExpiresFromConfig())) * time.Second + redis.SetByExpire("", "session_token", token, expireTime) c.Request.Header.Set("Accesstoken", token) } diff --git a/src/modules/common/controller/account.go b/src/modules/common/controller/account.go index 4e137aa..02e690d 100644 --- a/src/modules/common/controller/account.go +++ b/src/modules/common/controller/account.go @@ -134,7 +134,7 @@ func (s *AccountController) Logout(c *gin.Context) { os, browser := ctxUtils.UaOsBrowser(c) // 创建系统访问记录 s.sysLogLoginService.NewSysLogLogin( - userName, commonConstants.STATUS_NO, "退出成功", + userName, commonConstants.STATUS_YES, "退出成功", ipaddr, location, os, browser, ) } diff --git a/src/modules/system/controller/sys_menu.go b/src/modules/system/controller/sys_menu.go index 6e75ee7..5dfd4e4 100644 --- a/src/modules/system/controller/sys_menu.go +++ b/src/modules/system/controller/sys_menu.go @@ -79,7 +79,7 @@ func (s *SysMenuController) Add(c *gin.Context) { // 目录和菜单检查地址唯一 if menu.TYPE_DIR == body.MenuType || menu.TYPE_MENU == body.MenuType { - uniqueNenuPath := s.sysMenuService.CheckUniqueMenuPath(body.Path, "") + uniqueNenuPath := s.sysMenuService.CheckUniqueMenuPath(body.Path, body.ParentID, "") if !uniqueNenuPath { msg := fmt.Sprintf("菜单新增【%s】失败,菜单路由地址已存在", body.MenuName) c.JSON(200, result.ErrMsg(msg)) @@ -151,7 +151,7 @@ func (s *SysMenuController) Edit(c *gin.Context) { // 目录和菜单检查地址唯一 if menu.TYPE_DIR == body.MenuType || menu.TYPE_MENU == body.MenuType { - uniqueNenuPath := s.sysMenuService.CheckUniqueMenuPath(body.Path, body.MenuID) + uniqueNenuPath := s.sysMenuService.CheckUniqueMenuPath(body.Path, body.ParentID, body.MenuID) if !uniqueNenuPath { msg := fmt.Sprintf("菜单修改【%s】失败,菜单路由地址已存在", body.MenuName) c.JSON(200, result.ErrMsg(msg)) diff --git a/src/modules/system/service/sys_menu.go b/src/modules/system/service/sys_menu.go index 10374be..e4fbd5e 100644 --- a/src/modules/system/service/sys_menu.go +++ b/src/modules/system/service/sys_menu.go @@ -44,7 +44,7 @@ type ISysMenu interface { CheckUniqueMenuName(menuName, parentId, menuId string) bool // CheckUniqueMenuPath 校验路由地址是否唯一(针对目录和菜单) - CheckUniqueMenuPath(path, menuId string) bool + CheckUniqueMenuPath(path, parentId, menuId string) bool // BuildRouteMenus 构建前端路由所需要的菜单 BuildRouteMenus(sysMenus []model.SysMenu, prefix string) []vo.Router diff --git a/src/modules/system/service/sys_menu.impl.go b/src/modules/system/service/sys_menu.impl.go index 1dd1d83..6d4d5c2 100644 --- a/src/modules/system/service/sys_menu.impl.go +++ b/src/modules/system/service/sys_menu.impl.go @@ -124,9 +124,10 @@ func (r *SysMenuImpl) CheckUniqueMenuName(menuName, parentId, menuId string) boo } // CheckUniqueMenuPath 校验路由地址是否唯一(针对目录和菜单) -func (r *SysMenuImpl) CheckUniqueMenuPath(path, menuId string) bool { +func (r *SysMenuImpl) CheckUniqueMenuPath(path, parentId, menuId string) bool { uniqueId := r.sysMenuRepository.CheckUniqueMenu(model.SysMenu{ - Path: path, + Path: path, + ParentID: parentId, }) if uniqueId == menuId { return true