Browse Source

add 权限

master
dengbiao 3 weeks ago
parent
commit
c0ae8f38de
12 changed files with 526 additions and 4 deletions
  1. +37
    -0
      app/enum/enum_admin.go
  2. +19
    -0
      app/enum/enum_permission_group.go
  3. +108
    -0
      app/hdl/comm/hdl_comm.go
  4. +4
    -0
      app/md/app_redis_key.go
  5. +99
    -0
      app/md/md_role.go
  6. +5
    -0
      app/md/md_white_uri.go
  7. +33
    -0
      app/mw/mw_admin_permission.go
  8. +1
    -1
      app/mw/mw_cors.go
  9. +1
    -1
      app/mw/mw_limiter.go
  10. +8
    -2
      app/router/router.go
  11. +195
    -0
      app/svc/svc_role.go
  12. +16
    -0
      app/utils/url.go

+ 37
- 0
app/enum/enum_admin.go View File

@@ -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 "未知"
}
}

+ 19
- 0
app/enum/enum_permission_group.go View File

@@ -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 "未知"
}
}

+ 108
- 0
app/hdl/comm/hdl_comm.go View File

@@ -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
}

+ 4
- 0
app/md/app_redis_key.go View File

@@ -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
)

+ 99
- 0
app/md/md_role.go View File

@@ -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"`
}

+ 5
- 0
app/md/md_white_uri.go View File

@@ -0,0 +1,5 @@
package md

var WhiteUri = []string{
"/api/admin/comm/getMenuList",
}

+ 33
- 0
app/mw/mw_admin_permission.go View File

@@ -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()
}
}

+ 1
- 1
app/mw/mw_cors.go View File

@@ -4,7 +4,7 @@ import (
"github.com/gin-gonic/gin"
)

// cors跨域
// Cors 跨域
func Cors(c *gin.Context) {
// 放行所有OPTIONS方法
if c.Request.Method == "OPTIONS" {


+ 1
- 1
app/mw/mw_limiter.go View File

@@ -10,7 +10,7 @@ import (
"applet/app/utils/cache"
)

// 限流器
// Limiter 限流器
func Limiter(c *gin.Context) {
limit := 100 // 限流次数
ttl := 1 // 限流过期时间


+ 8
- 2
app/router/router.go View File

@@ -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) // 获取菜单栏列表
}

+ 195
- 0
app/svc/svc_role.go View File

@@ -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()
}

+ 16
- 0
app/utils/url.go View File

@@ -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, "/")
}

Loading…
Cancel
Save