From c0ae8f38deda1f4a80516504f158f5892d1101e4 Mon Sep 17 00:00:00 2001 From: dengbiao Date: Thu, 7 Nov 2024 18:27:34 +0800 Subject: [PATCH] =?UTF-8?q?add=20=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/enum/enum_admin.go | 37 ++++++ app/enum/enum_permission_group.go | 19 +++ app/hdl/comm/hdl_comm.go | 108 +++++++++++++++++ app/md/app_redis_key.go | 4 + app/md/md_role.go | 99 +++++++++++++++ app/md/md_white_uri.go | 5 + app/mw/mw_admin_permission.go | 33 +++++ app/mw/mw_cors.go | 2 +- app/mw/mw_limiter.go | 2 +- app/router/router.go | 10 +- app/svc/svc_role.go | 195 ++++++++++++++++++++++++++++++ app/utils/url.go | 16 +++ 12 files changed, 526 insertions(+), 4 deletions(-) create mode 100644 app/enum/enum_admin.go create mode 100644 app/enum/enum_permission_group.go create mode 100644 app/hdl/comm/hdl_comm.go create mode 100644 app/md/md_role.go create mode 100644 app/md/md_white_uri.go create mode 100644 app/mw/mw_admin_permission.go create mode 100644 app/svc/svc_role.go create mode 100644 app/utils/url.go diff --git a/app/enum/enum_admin.go b/app/enum/enum_admin.go new file mode 100644 index 0000000..e69c56d --- /dev/null +++ b/app/enum/enum_admin.go @@ -0,0 +1,37 @@ +package enum + +type AdminState int32 + +const ( + AdminStateForNormal = 1 + AdminStateForFreeze = 2 +) + +func (gt AdminState) String() string { + switch gt { + case AdminStateForNormal: + return "正常" + case AdminStateForFreeze: + return "冻结" + default: + return "未知" + } +} + +type IsSuperAdministrator int32 + +const ( + IsSuperAdministratorTure = 1 + IsSuperAdministratorFalse = 2 +) + +func (gt IsSuperAdministrator) String() string { + switch gt { + case IsSuperAdministratorTure: + return "超管" + case IsSuperAdministratorFalse: + return "非超管" + default: + return "未知" + } +} diff --git a/app/enum/enum_permission_group.go b/app/enum/enum_permission_group.go new file mode 100644 index 0000000..eda844a --- /dev/null +++ b/app/enum/enum_permission_group.go @@ -0,0 +1,19 @@ +package enum + +type PermissionGroupState int32 + +const ( + PermissionGroupStateForNormal = 1 + PermissionGroupStateForDiscard = 2 +) + +func (gt PermissionGroupState) String() string { + switch gt { + case PermissionGroupStateForNormal: + return "正常" + case PermissionGroupStateForDiscard: + return "废弃" + default: + return "未知" + } +} diff --git a/app/hdl/comm/hdl_comm.go b/app/hdl/comm/hdl_comm.go new file mode 100644 index 0000000..3461031 --- /dev/null +++ b/app/hdl/comm/hdl_comm.go @@ -0,0 +1,108 @@ +package comm + +import ( + "applet/app/db" + "applet/app/e" + "applet/app/enum" + "applet/app/md" + "applet/app/svc" + "applet/app/utils" + "code.fnuoos.com/EggPlanet/egg_models.git/src/implement" + "github.com/gin-gonic/gin" +) + +func MenuList(c *gin.Context) { + engine := db.Db + admin := svc.GetUser(c) + qrcodeWithBatchRecordsDb := implement.NewPermissionGroupDb(engine) + groupList, err := qrcodeWithBatchRecordsDb.FindPermissionGroupV2() + if err != nil { + e.OutErr(c, e.ERR_DB_ORM, err.Error()) + return + } + + // 1、查询出当前用户所有角色 + adminRoleDb := implement.NewAdminRoleDb(engine) + roles, err := adminRoleDb.FindAdminRole(admin.AdmId) + if err != nil { + e.OutErr(c, e.ERR_DB_ORM, err.Error()) + return + } + + roleDb := implement.NewRoleDb(engine, 0) + var adminHasPermissionGroupIds []string + for _, v := range *roles { + list, _, err1 := roleDb.FindPermissionGroupByRole(v.RoleId) + if err1 != nil { + e.OutErr(c, e.ERR_DB_ORM, err1.Error()) + return + } + for _, v1 := range list { + adminHasPermissionGroupIds = append(adminHasPermissionGroupIds, utils.IntToStr(v1.PermissionGroup.Id)) + } + } + + var tempRespMap = map[string]*md.PermissionGroupListResp{} + var tempRespMapKeys []string + for _, v := range *groupList { + + var isCheck bool + if admin.IsSuperAdministrator == enum.IsSuperAdministratorTure { + isCheck = true + } else { + isCheck = false + } + + if utils.InArr(utils.IntToStr(v.Id), adminHasPermissionGroupIds) { + isCheck = true + } + + if v.State == enum.PermissionGroupStateForDiscard { + isCheck = false + } + + tempRespMap[utils.IntToStr(v.Id)] = &md.PermissionGroupListResp{ + Id: v.Id, + Name: v.Name, + Key: v.Key, + State: v.State, + ParentId: v.ParentId, + CreateAt: v.CreateAt, + UpdateAt: v.UpdateAt, + IsCheck: isCheck, + } + tempRespMapKeys = append(tempRespMapKeys, utils.IntToStr(v.Id)) + } + for _, v := range tempRespMap { + if v.ParentId != 0 && tempRespMap[utils.IntToStr(v.ParentId)].ParentId != 0 { + tempRespMap[utils.IntToStr(v.ParentId)].SubPermissionGroupList = append(tempRespMap[utils.IntToStr(v.ParentId)].SubPermissionGroupList, *v) + } + } + for _, v := range tempRespMap { + if v.ParentId != 0 && tempRespMap[utils.IntToStr(v.ParentId)].ParentId == 0 { + tempRespMap[utils.IntToStr(v.ParentId)].SubPermissionGroupList = append(tempRespMap[utils.IntToStr(v.ParentId)].SubPermissionGroupList, *v) + } + } + + var resp []*md.PermissionGroupListResp + for _, v := range tempRespMapKeys { + if tempRespMap[v].ParentId == 0 { + resp = append(resp, tempRespMap[v]) + } + } + + e.OutSuc(c, map[string]interface{}{ + "list": resp, + "state": []map[string]interface{}{ + { + "name": enum.PermissionGroupState(enum.PermissionGroupStateForNormal).String(), + "value": enum.PermissionGroupStateForNormal, + }, + { + "name": enum.PermissionGroupState(enum.PermissionGroupStateForDiscard).String(), + "value": enum.PermissionGroupStateForDiscard, + }, + }, + }, nil) + return +} diff --git a/app/md/app_redis_key.go b/app/md/app_redis_key.go index 7bf090c..fb85fa6 100644 --- a/app/md/app_redis_key.go +++ b/app/md/app_redis_key.go @@ -9,4 +9,8 @@ const ( AppCfgCacheKey = "cfg_cache:%s" // 占位符: key的第一个字母 CfgCacheTime = 86400 + + AdminRolePermissionKey = "egg_admin_role_permission:%s" // 占位符:admin:id + + AdminRolePermissionCacheTime = 3600 * 24 * 0.5 ) diff --git a/app/md/md_role.go b/app/md/md_role.go new file mode 100644 index 0000000..5e8c173 --- /dev/null +++ b/app/md/md_role.go @@ -0,0 +1,99 @@ +package md + +import ( + "code.fnuoos.com/EggPlanet/egg_models.git/src/model" +) + +type RoleListResp struct { + Data model.Role `json:"data"` + AdminList []struct { + Name string `json:"name"` + } `json:"admin_list"` +} + +type UpdateRoleStateReq struct { + RoleId int `json:"role_id" binding:"required" label:"id"` + State int `json:"state" binding:"required" label:"状态"` +} + +type AddRoleReq struct { + Name string `json:"name" binding:"required" label:"名称"` + Memo string `json:"memo" binding:"required" label:"备注"` + Logo string `json:"logo" label:"左边图标"` + Label string `json:"label" label:"身份标签"` + SeoLogo string `json:"seo_logo" label:"seo"` + SeoTitle string `json:"seo_title" label:"seo"` +} + +type UpdateRoleReq struct { + RoleId int `json:"role_id" binding:"required" label:"id"` + Name string `json:"name" binding:"required" label:"名称"` + Memo string `json:"memo" binding:"required" label:"备注"` + Logo string `json:"logo" label:"左边图标"` + Label string `json:"label" label:"身份标签"` + SeoLogo string `json:"seo_logo" label:"seo"` + SeoTitle string `json:"seo_title" label:"seo"` +} + +type RoleBindPermissionGroupReq struct { + RoleId int `json:"role_id" binding:"required" label:"id"` + PermissionIds []int `json:"permission_ids" label:"权限组id"` +} + +type PermissionGroupListResp struct { + Id int `json:"id"` + Name string `json:"name"` //菜单名称 + Key string `json:"key"` //唯一标识符 + State int `json:"state"` + ParentId int `json:"parent_id"` //父级id,为0则代表没有父级 + CreateAt string `json:"create_at"` + UpdateAt string `json:"update_at"` + IsCheck bool `json:"is_check"` //是否用用 + SubPermissionGroupList []PermissionGroupListResp `json:"sub_permission_group_list"` //子集菜单 +} + +type AdminListReq struct { + Limit int `json:"limit"` + Page int `json:"page" ` + UserName string `json:"username"` + State int `json:"state"` +} + +type AdminListResp struct { + AdmId int `json:"adm_id"` + Username string `json:"username"` + State int `json:"state"` + IsSuperAdministrator int `json:"is_super_administrator"` + Memo string `json:"memo"` + CreateAt string `json:"create_at"` + UpdateAt string `json:"update_at"` + RoleList []string `json:"role_list"` +} + +type UpdateAdminStateReq struct { + AdmId int `json:"adm_id" binding:"required" label:"管理员id"` + State int `json:"state" binding:"required" label:"状态"` +} + +type AddAdminReq struct { + Username string `json:"username" binding:"required" label:"名称"` + Password string `json:"password" binding:"required" label:"密码"` + Memo string `json:"memo" label:"备注"` +} + +type UpdateAdminReq struct { + AdmId int `json:"adm_id" binding:"required" label:"管理员id"` + Username string `json:"username" binding:"required" label:"名称"` + Password string `json:"password" binding:"required" label:"密码"` + Memo string `json:"memo" label:"备注"` +} + +type BindAdminRoleReq struct { + AdmId int `json:"adm_id" binding:"required" label:"管理员id"` + RoleIds []int `json:"role_ids" label:"角色id"` +} + +type BindAdminWithEnterpriseReq struct { + AdmId int `json:"adm_id" binding:"required" label:"管理员id"` + Ids []int `json:"ids" label:"记录id"` +} diff --git a/app/md/md_white_uri.go b/app/md/md_white_uri.go new file mode 100644 index 0000000..b5c54d7 --- /dev/null +++ b/app/md/md_white_uri.go @@ -0,0 +1,5 @@ +package md + +var WhiteUri = []string{ + "/api/admin/comm/getMenuList", +} diff --git a/app/mw/mw_admin_permission.go b/app/mw/mw_admin_permission.go new file mode 100644 index 0000000..4165ee6 --- /dev/null +++ b/app/mw/mw_admin_permission.go @@ -0,0 +1,33 @@ +package mw + +import ( + "applet/app/e" + "applet/app/enum" + "applet/app/md" + "applet/app/svc" + "applet/app/utils" + "fmt" + "github.com/gin-gonic/gin" +) + +// CheckPermission 检查权限 +func CheckPermission(c *gin.Context) { + admin := svc.GetUser(c) + + // TODO::判断是否为超管 + if admin.IsSuperAdministrator == enum.IsSuperAdministratorTure { + c.Next() + } else { + rolePermissionKey := fmt.Sprintf(md.AdminRolePermissionKey, utils.AnyToString(admin.AdmId)) + isHasPermission, err := svc.CheckUserRole(c, rolePermissionKey, c.Request.RequestURI, admin.AdmId) + if err != nil { + e.OutErr(c, e.ERR, err.Error()) + return + } + if !isHasPermission { + e.OutErr(c, e.ERR_FORBIDEN, "当前用户暂未拥有该路由权限,请联系管理员") + return + } + c.Next() + } +} diff --git a/app/mw/mw_cors.go b/app/mw/mw_cors.go index 3433553..1151639 100644 --- a/app/mw/mw_cors.go +++ b/app/mw/mw_cors.go @@ -4,7 +4,7 @@ import ( "github.com/gin-gonic/gin" ) -// cors跨域 +// Cors 跨域 func Cors(c *gin.Context) { // 放行所有OPTIONS方法 if c.Request.Method == "OPTIONS" { diff --git a/app/mw/mw_limiter.go b/app/mw/mw_limiter.go index 4eb5299..7171002 100644 --- a/app/mw/mw_limiter.go +++ b/app/mw/mw_limiter.go @@ -10,7 +10,7 @@ import ( "applet/app/utils/cache" ) -// 限流器 +// Limiter 限流器 func Limiter(c *gin.Context) { limit := 100 // 限流次数 ttl := 1 // 限流过期时间 diff --git a/app/router/router.go b/app/router/router.go index a34b248..1a4e675 100644 --- a/app/router/router.go +++ b/app/router/router.go @@ -3,6 +3,7 @@ package router import ( "applet/app/cfg" "applet/app/hdl" + "applet/app/hdl/comm" "applet/app/hdl/institutional_management/public_platoon" "applet/app/mw" _ "applet/docs" @@ -49,9 +50,10 @@ func Init() *gin.Engine { func route(r *gin.RouterGroup) { r.GET("/test", hdl.Demo) r.POST("/login", hdl.Login) - rInstitutionalManagement(r.Group("/institutionalManagement")) r.Use(mw.Auth) // 以下接口需要JWT验证 - + rComm(r.Group("/comm")) + r.Use(mw.CheckPermission) // 检测权限 + rInstitutionalManagement(r.Group("/institutionalManagement")) } func rInstitutionalManagement(r *gin.RouterGroup) { //制度管理 @@ -60,3 +62,7 @@ func rInstitutionalManagement(r *gin.RouterGroup) { //制度管理 rPublicPlatoon.GET("/getBasic", public_platoon.GetPublicPlatoonBasic) } } + +func rComm(r *gin.RouterGroup) { + r.POST("/getMenuList", comm.MenuList) // 获取菜单栏列表 +} diff --git a/app/svc/svc_role.go b/app/svc/svc_role.go new file mode 100644 index 0000000..3e3f8e6 --- /dev/null +++ b/app/svc/svc_role.go @@ -0,0 +1,195 @@ +package svc + +import ( + "applet/app/db" + "applet/app/md" + "applet/app/utils" + "applet/app/utils/cache" + "code.fnuoos.com/EggPlanet/egg_models.git/src/implement" + "code.fnuoos.com/EggPlanet/egg_models.git/src/model" + "encoding/json" + "errors" + "fmt" + "github.com/gin-gonic/gin" + "regexp" + "strings" + "time" +) + +func CheckUserRole(c *gin.Context, cacheKey, uri string, admId int) (isHasPermission bool, err error) { + uri = utils.UriFilterExcludeQueryString(uri) // 去除uri中?后的query参数 + isHasPermission = false + var rolePermission []string + var rolePermissionString string + rolePermissionString, _ = cache.GetString(cacheKey) + + // TODO::判断是否在白名单中 + if utils.InArr(uri, md.WhiteUri) { + isHasPermission = true + return + } + + if rolePermissionString != "" { + // if false { + if err = json.Unmarshal([]byte(rolePermissionString), &rolePermission); err != nil { + return + } + } else { + adminDb := implement.NewAdminDb(db.Db) + list, _, err1 := adminDb.GetAdminRolePermission(admId) + if err1 != nil { + return isHasPermission, err1 + } + for _, v := range list { + rolePermission = append(rolePermission, v.Permission.Action) + } + marshal, err1 := json.Marshal(rolePermission) + if err1 != nil { + return isHasPermission, err1 + } + rolePermissionString = string(marshal) + _, err = cache.SetEx(cacheKey, rolePermissionString, md.AdminRolePermissionCacheTime) + } + + if utils.InArr(uri, rolePermission) { + isHasPermission = true + } else { + // 正则匹配占位符情况 + compileRegex := regexp.MustCompile("[0-9]+") + matchArr := compileRegex.FindAllString(uri, -1) + if len(matchArr) > 0 { + uri = strings.Replace(uri, matchArr[len(matchArr)-1], ":id", 1) + if utils.InArr(uri, rolePermission) { + isHasPermission = true + } + } + } + return +} + +func DeleteRole(c *gin.Context, roleId int) (err error) { + engine := db.Db + session := engine.NewSession() + defer session.Close() + session.Begin() + + // 1、删除 `role` + roleDb := implement.NewRoleDb(engine, roleId) + _, err = roleDb.RoleDeleteBySession(session, roleId) + if err != nil { + _ = session.Rollback() + return + } + + // 2、删除 `role_permission_group` + rolePermissionGroupDb := implement.NewRolePermissionGroupDb(db.Db) + _, err = rolePermissionGroupDb.RolePermissionGroupDeleteForRoleBySession(session, roleId) + if err != nil { + _ = session.Rollback() + return + } + + // 3、删除 `admin_role` + adminRoleDb := implement.NewAdminRoleDb(db.Db) + _, err = adminRoleDb.AdminRoleDeleteForRoleBySession(session, roleId) + if err != nil { + _ = session.Rollback() + return + } + + return session.Commit() +} + +func RoleBindPermissionGroup(c *gin.Context, req md.RoleBindPermissionGroupReq) (err error) { + engine := db.Db + session := engine.NewSession() + defer session.Close() + session.Begin() + // 1、查询 `role` + roleDb := implement.NewRoleDb(db.Db, req.RoleId) + role, err := roleDb.GetRole() + if err != nil { + return + } + if role == nil { + return errors.New("未查询到相应记录") + } + + // 1、删除 `role_permission_group` + rolePermissionGroupDb := implement.NewRolePermissionGroupDb(db.Db) + _, err = rolePermissionGroupDb.RolePermissionGroupDeleteForRoleBySession(session, req.RoleId) + if err != nil { + _ = session.Rollback() + return + } + + // 2、新增 `role_permission_group`` + var mm []*model.RolePermissionGroup + now := time.Now() + for _, v := range req.PermissionIds { + mm = append(mm, &model.RolePermissionGroup{ + RoleId: role.Id, + GroupId: v, + CreateAt: now.Format("2006-01-02 15:04:05"), + UpdateAt: now.Format("2006-01-02 15:04:05"), + }) + } + _, err = rolePermissionGroupDb.BatchAddRolePermissionGroupBySession(session, mm) + if err != nil { + _ = session.Rollback() + return + } + + session.Commit() + var data []model.AdminRole + engine.Where("role_id=?", role.Id).Find(&data) + for _, v := range data { + rolePermissionKey := fmt.Sprintf(md.AdminRolePermissionKey, utils.AnyToString(v.AdmId)) + cache.Del(rolePermissionKey) + } + return nil +} + +func BindAdminRole(c *gin.Context, req md.BindAdminRoleReq) (err error) { + engine := db.Db + session := engine.NewSession() + defer session.Close() + session.Begin() + // 1、查询 `role` + adminDb := implement.NewAdminDb(db.Db) + role, err := adminDb.GetAdmin(req.AdmId) + if err != nil { + return + } + if role == nil { + return errors.New("未查询到相应记录") + } + + // 1、删除 `admin_role` + adminRoleDb := implement.NewAdminRoleDb(db.Db) + _, err = adminRoleDb.AdminRoleDeleteBySession(session, req.AdmId) + if err != nil { + _ = session.Rollback() + return + } + + // 2、新增 `删除 `admin_role`` + var mm []*model.AdminRole + now := time.Now() + for _, v := range req.RoleIds { + mm = append(mm, &model.AdminRole{ + AdmId: req.AdmId, + RoleId: v, + State: 1, + CreateAt: now.Format("2006-01-02 15:04:05"), + UpdateAt: now.Format("2006-01-02 15:04:05"), + }) + } + _, err = adminRoleDb.BatchAddAdminRoleBySession(session, mm) + if err != nil { + _ = session.Rollback() + return + } + + return session.Commit() +} diff --git a/app/utils/url.go b/app/utils/url.go new file mode 100644 index 0000000..f0c7d6b --- /dev/null +++ b/app/utils/url.go @@ -0,0 +1,16 @@ +package utils + +import ( + "net/url" + "strings" +) + +func UriFilterExcludeQueryString(uri string) string { + URL, _ := url.Parse(uri) + + clearUri := strings.ReplaceAll(uri, URL.RawQuery, "") + + clearUri = strings.TrimRight(clearUri, "?") + + return strings.TrimRight(clearUri, "/") +}