Files
yunzerwebsiteallinone/go/services/permission.go
T
2026-10-19 01:13:17 +08:00

93 lines
2.7 KiB
Go

package services
import (
"encoding/json"
"strconv"
"strings"
"server/models"
)
// ParseMenuRights 将角色 rights 解析为菜单 ID 集合(兼容 JSON 数组 / 逗号分隔)。
// 数字数组是角色保存接口 json.Marshal([]uint64) 写回的规范格式,必须支持;
// 若只按 []string 反序列化会整体失败并退化成逗号切分,
// 首尾元素会带上 [ / ] 而解析不出数字,导致第一个和最后一个菜单被静默丢弃。
func ParseMenuRights(raw string) map[uint64]bool {
set := map[uint64]bool{}
var arr []interface{}
if err := json.Unmarshal([]byte(raw), &arr); err == nil {
for _, v := range arr {
if n := menuIDOf(v); n > 0 {
set[n] = true
}
}
return set
}
for _, s := range strings.Split(raw, ",") {
if n, e := strconv.ParseUint(strings.TrimSpace(s), 10, 64); e == nil {
set[n] = true
}
}
return set
}
// menuIDOf 把 JSON 元素(数字或字符串)转成菜单 ID,无效时返回 0
func menuIDOf(v interface{}) uint64 {
switch t := v.(type) {
case float64:
if t > 0 {
return uint64(t)
}
case string:
if n, e := strconv.ParseUint(strings.TrimSpace(t), 10, 64); e == nil {
return n
}
}
return 0
}
// CheckUserPermission 校验用户是否拥有指定权限标识。
// rights 里存的是菜单 ID 而不是权限串,必须经 yz_system_menu.permission 换算后再比对;
// 直接拿 rights 元素和权限串比永远不相等,会把本来有权限的角色全部判成无权访问。
// rights 为空(nil / 空串)视为全权限,与菜单过滤 filterMenusByRights 口径一致;
// rights 有内容却解析不出任何菜单 ID(历史脏数据)按无权限处理,不放行。
func CheckUserPermission(userID int, permission string) (bool, error) {
if permission == "" || userID <= 0 {
return true, nil
}
var user models.AdminUser
if err := models.Orm.QueryTable(new(models.AdminUser)).Filter("id", userID).One(&user); err != nil {
return false, err
}
var role models.AdminRole
if err := models.Orm.QueryTable(new(models.AdminRole)).Filter("id", user.RoleID).One(&role); err != nil {
return false, err
}
if role.Rights == nil || strings.TrimSpace(*role.Rights) == "" {
return true, nil
}
menuIDs := ParseMenuRights(*role.Rights)
if len(menuIDs) == 0 {
return false, nil
}
idList := make([]uint64, 0, len(menuIDs))
for id := range menuIDs {
idList = append(idList, id)
}
// 只有启用且未删除的菜单才能授予权限,禁用的菜单不应继续放行其权限标识
count, err := models.Orm.QueryTable(new(models.SystemMenu)).
Filter("id__in", idList).
Filter("permission", permission).
Filter("status", 1).
Filter("delete_time__isnull", true).
Count()
if err != nil {
return false, err
}
return count > 0, nil
}