| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 | package iiimport (	"os"	"path/filepath"	"strings"	"golib/v2/features/mo")// Perms 权限, 由每个键值组成.// 示例: "PERM.OWN": [{"creator": "SIMANC"}],type Perms map[string]mo.A// Has 是否包含 perm 权限func (p Perms) Has(s string) bool {	_, ok := p[s]	return ok}func (p Perms) HasAll(s []string) bool {	if len(s) == 0 {		return false	}	for _, sp := range s {		if _, ok := p[sp]; !ok {			return false		}	}	return true}func (p Perms) handleD(ele mo.D, u User) {	for j, e := range ele {		if el, ok := e.Value.(mo.D); ok {			p.handleD(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) handleA(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.handleA(el, u)			} else {				p.handleD(ele, u)			}		}		cond[i] = ele	}	return cond}// Get 获取权限func (p Perms) Get(s string, u User) (mo.D, bool) {	pm, ok := p[s]	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.handleA(perm[s], u)	perms := make(mo.D, 0)	for _, ele := range cond {		perms = append(perms, ele.(mo.D)...)	}	return perms, true}func (p Perms) GetAll(s []string, u User) (mo.D, bool) {	if len(s) == 0 {		return nil, false	}	perm := make(mo.D, 0, len(s))	for _, sp := range s {		cond, ok := p.Get(sp, u)		if !ok {			return nil, false		}		perm = append(perm, cond...)	}	return perm, true}type GroupMeta struct {	Label string              `json:"label"`	Role  map[string][]string `json:"role"`}// Group 用户组// 用户组包含用户组名称和该名称下用户角色和权限的对应关系type Group map[string]GroupMeta// Has 是否在用户组内// name 为用户组名称, role 为用户组内的角色// 若需要 Has 返回 true, 则用户首先应在当前用户组内, 其次 user.role 需要有对应当前用户组的角色且 group 内也有对应的角色权限控制////	{//	 "groupName": {//	   "label": "用户组",//	   "role": {//	     "manager": [],//	     "user": [],//	     "...": []//	   }//	 }//	}func (g Group) Has(name, role string) bool {	meta, ok := g[name]	if !ok {		return false	}	_, ok = meta.Role[role]	return ok}// Get 获取用户组对应角色下的权限// 返回的结果应当在 Perms 内转换为条件func (g Group) Get(name, role string) ([]string, bool) {	meta, ok := g[name]	if !ok {		return nil, false	}	cond, ok := meta.Role[role]	if !ok {		return nil, false	}	return cond, len(cond) > 0}// Role 角色type Role map[string]string// Has 是否包含角色 sfunc (r Role) Has(s string) bool {	_, ok := r[s]	return ok}type DbPerms struct {	Label      string   `json:"label"`	Group      string   `json:"group"`      // 所属用户组	OtherPerms []string `json:"otherPerms"` // 用户组之外的用户使用此权限查询}// Database 数据库表的权限type Database map[Name]DbPerms// Has 查询 name 是否在 group 用户组中func (d Database) Has(name Name, group string) bool {	db, ok := d[name]	if !ok {		// 未找到此数据库表		return false	}	return db.Group == group}// GetGroup 获取数据库表所需要的用户组func (d Database) GetGroup(name Name) string {	db, ok := d[name]	if !ok {		// 未找到此数据库表		return ""	}	return db.Group}func (d Database) GetOtherPerms(name Name) []string {	db, ok := d[name]	if !ok {		return nil	}	return db.OtherPerms}type Permission interface {	Has(name Name, u User) (mo.D, bool)}type PermsConfig struct {	Perms    Perms    `json:"perms"`	Group    Group    `json:"group"`	Role     Role     `json:"role"`	Database Database `json:"database"`}func (p *PermsConfig) Has(name Name, u User) (mo.D, bool) {	if u.IsSysadmin() {		return nil, true	}	// 查询数据库表所需要的用户组	group := p.Database.GetGroup(name)	// 如果用户不在数据库表要求的用户组时	if !u.Group(group) {		// 检查数据库是否允许 other 访问, 当 other 的权限数量 > 0 时表示有权限访问, 否则表示无权限		return p.Perms.GetAll(p.Database.GetOtherPerms(name), u)	}	// 如果用户在数据库表要求的用户组	// 获取用户在当前用户组的角色	role, ok := u.Role(group)	// 如果该用户没有当前用户组的角色时	if !ok {		// 检查数据库是否允许 other 访问, 当 other 的权限数量 > 0 时表示有权限访问, 否则表示无权限		return p.Perms.GetAll(p.Database.GetOtherPerms(name), u)	}	// 若用户在当前用户组的角色无效时	if !p.Role.Has(role) {		// 检查数据库是否允许 other 访问, 当 other 的权限数量 > 0 时表示有权限访问, 否则表示无权限		return p.Perms.GetAll(p.Database.GetOtherPerms(name), u)	}	// 检查用户是否有自定义该用户组角色的权限	perms, ok := u.Perms(group)	if ok {		// 如果用户的角色未在用户组配置时		if !p.Group.Has(group, role) {			// 检查数据库是否允许 other 访问, 当 other 的权限数量 > 0 时表示有权限访问, 否则表示无权限			return p.Perms.GetAll(p.Database.GetOtherPerms(name), u)		}	} else {		// 获取用户组包含的权限		perms, ok = p.Group.Get(group, role)		// 如果当前用户组内没有包含当前用户角色的权限		if !ok {			// 检查数据库是否允许 other 访问, 当 other 的权限数量 > 0 时表示有权限访问, 否则表示无权限			return p.Perms.GetAll(p.Database.GetOtherPerms(name), u)		}	}	// 当用户组所需要的权限在权限列表中全部匹配时表示有权限访问	return p.Perms.GetAll(perms, u)}func LoadPerms(name string) (Permission, error) {	b, err := os.ReadFile(filepath.Join(name))	if err != nil {		return nil, err	}	var perms PermsConfig	if err = mo.UnmarshalExtJSON(b, true, &perms); err != nil {		return nil, err	}	return &perms, err}
 |