| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 | package iiimport (	"os"	"path/filepath"	"strings"	"golib/v4/features/mo")// Perms 权限, 由每个键值组成.// 示例: "PERM.OWN": [{"creator": "SIMANC"}],// key / cond 即关键字与条件type Perms map[string]mo.A// Has 是否包含 perm 权限func (p Perms) Has(key string) bool {	_, ok := p[key]	return ok}func (p Perms) HasAll(keys []string) bool {	if len(keys) == 0 {		return false	}	for _, key := range keys {		if _, ok := p[key]; !ok {			return false		}	}	return true}func (p Perms) getCondElement(ele mo.D, u User) {	for j, e := range ele {		if el, ok := e.Value.(mo.D); ok {			p.getCondElement(el, u)		}		switch e.Value {		case "$id":			ele[j] = mo.E{Key: e.Key, Value: u.ID()}		case "$name":			ele[j] = mo.E{Key: e.Key, Value: u.Name()}		case "$company":			ele[j] = mo.E{Key: e.Key, Value: u.Company()}		case "$companyALL":			ele[j] = mo.E{Key: e.Key, Value: u.CompanyALL()}		default:			str, ok := e.Value.(string)			if !ok && strings.Count(str, ".") != 1 {				continue			}			kk, kv, _ := strings.Cut(str, ".")			if !strings.HasPrefix(kk, "$") || !strings.HasPrefix(kv, "$") {				continue			}			kk = strings.TrimPrefix(kk, "$")			kv = strings.TrimPrefix(kv, "$")			vMap, ok := u.Get(kk).(mo.M)			if !ok {				continue			}			if v, o := vMap[kv]; o {				ele[j] = mo.E{Key: e.Key, Value: v}			}		}	}}func (p Perms) getCondFrom(cond mo.A, u User) mo.A {	for i, doc := range cond {		ele, o := doc.(mo.D)		if !o {			panic("element must be type mo.D")		}		for _, e := range ele {			if el, ok := e.Value.(mo.A); ok {				p.getCondFrom(el, u)			} else {				p.getCondElement(ele, u)			}		}		cond[i] = ele	}	return cond}// getFilterFrom 获取单个 ket 的过滤器func (p Perms) getFilterFrom(key string, u User) (filter mo.D, accessible bool) {	pm, ok := p[key]	if !ok {		return nil, false	}	// 如果存在该权限, 但权限配置为空, 则表示拥有所有权限	if len(pm) == 0 {		return nil, true	}	b, err := mo.MarshalExtJSON(p, true, true)	if err != nil {		return nil, false	}	var perm Perms	if err = mo.UnmarshalExtJSON(b, true, &perm); err != nil {		return nil, false	}	cond := p.getCondFrom(perm[key], u)	filter = make(mo.D, 0)	for _, ele := range cond {		filter = append(filter, ele.(mo.D)...)	}	return filter, true}func (p Perms) GetFilter(keys []string, u User) (filter mo.D, accessible bool) {	if len(keys) == 0 {		return nil, false	}	filter = make(mo.D, 0)	for _, key := range keys {		cond, ok := p.getFilterFrom(key, u)		if !ok {			return nil, false		}		filter = append(filter, cond...)	}	return filter, true}type PermGroupMeta struct {	Label string              `json:"label"`	Role  map[string][]string `json:"role"`}// PermGroup 用户组// 用户组包含用户组名称和该名称下用户角色和权限的对应关系type PermGroup map[string]PermGroupMeta// Has 是否在用户组内// group 为用户组名称, role 为用户组内的角色// 若需要 Has 返回 true, 则用户首先应在当前用户组内, 其次 user.role 需要有对应当前用户组的角色且 group 内也有对应的角色权限控制////	{//	 "groupName": {//	   "label": "用户组",//	   "role": {//	     "manager": [],//	     "user": [],//	     "...": []//	   }//	 }//	}func (g PermGroup) Has(group, role string) bool {	meta, ok := g[group]	if !ok {		return false	}	_, ok = meta.Role[role]	return ok}// GetKeys 获取用户组对应角色下的权限// 返回的结果应当在 Perms 内转换为条件func (g PermGroup) GetKeys(group, role string) (keys []string, found bool) {	meta, ok := g[group]	if !ok {		return nil, false	}	cond, ok := meta.Role[role]	if !ok {		return nil, false	}	return cond, len(cond) > 0}// PermRole 角色// map[role][label]type PermRole map[string]string// Has 是否包含角色 sfunc (r PermRole) Has(role string) bool {	_, ok := r[role]	return ok}type PermDbConfig struct {	Label      string   `json:"label"`	Group      string   `json:"group"`      // 所属用户组	OtherPerms []string `json:"otherPerms"` // Deprecated, 用户组之外的用户使用此权限查询	Keys       []string `json:"keys"`       // 用户组之外的用户使用此项查询}// PermDatabase 数据库表的权限type PermDatabase map[Name]PermDbConfig// Has 查询 itemName 是否在 group 用户组中func (d PermDatabase) Has(itemName Name, group string) bool {	db, ok := d[itemName]	if !ok {		// 未找到此数据库表		return false	}	return db.Group == group}// RequiredGroup 获取访问 itemName 所需要的用户组func (d PermDatabase) RequiredGroup(itemName Name) (groupName string) {	db, ok := d[itemName]	if !ok {		// 未找到此数据库表		return ""	}	return db.Group}// RequiredKeys 获取访问 itemName 所需要的 key// 如果当前用户没有 RequiredGroup 的用户组, 则可以尝试通过此方法再次检查访问权限func (d PermDatabase) RequiredKeys(itemName Name) (keys []string) {	db, ok := d[itemName]	if !ok {		return nil	}	return append(db.OtherPerms, db.Keys...)}type Permission interface {	Has(itemName Name, u User) (filter mo.D, accessible bool)}type PermsConfig struct {	Perms    Perms        `json:"perms"`	Group    PermGroup    `json:"group"`	Role     PermRole     `json:"role"`	Database PermDatabase `json:"database"`}// Has 检查 u 是否拥有访问 itemName 的权限. 如果没有权限访问, 则 accessible 为 false// 如果拥有访问权限, 则 filter 返回过滤条件func (p *PermsConfig) Has(itemName Name, u User) (filter mo.D, accessible bool) {	if u.IsSysadmin() {		return nil, true	}	// 查询数据库表所需要的用户组	reqGroup := p.Database.RequiredGroup(itemName)	reqKeys := p.Database.RequiredKeys(itemName)	// 如果用户不在数据库表要求的用户组时	if !u.Group(reqGroup) {		return p.Perms.GetFilter(reqKeys, u)	}	// 如果用户在数据库表要求的用户组	// 获取用户在当前用户组的角色	roleName, has := u.Role(reqGroup)	// 如果该用户没有当前用户组的角色时	if !has {		return p.Perms.GetFilter(reqKeys, u)	}	// 若用户在当前用户组的角色无效时	if !p.Role.Has(roleName) {		return p.Perms.GetFilter(reqKeys, u)	}	// 检查用户是否有自定义该用户组角色的 keys, 如果有则使用自定义角色的 keys	keys, found := u.Perms(reqGroup)	if found {		// 如果用户的角色未在用户组配置时		if !p.Group.Has(reqGroup, roleName) {			return p.Perms.GetFilter(p.Database.RequiredKeys(itemName), u)		}	} else {		keys, found = p.Group.GetKeys(reqGroup, roleName)		// 如果当前用户组内没有包含当前用户角色的权限		if !found {			return p.Perms.GetFilter(p.Database.RequiredKeys(itemName), u)		}	}	// 当用户组所需要的权限在权限列表中全部匹配时表示有权限访问	return p.Perms.GetFilter(keys, u)}func LoadPerms(fileName string) (Permission, error) {	b, err := os.ReadFile(filepath.Join(fileName))	if err != nil {		return nil, err	}	var perms PermsConfig	if err = mo.UnmarshalExtJSON(b, true, &perms); err != nil {		return nil, err	}	return &perms, err}
 |