package privilege import ( "fmt" "github.com/casbin/casbin/v2" "github.com/casbin/casbin/v2/model" xormadapter "github.com/casbin/xorm-adapter/v2" "github.com/civet148/log" "github.com/civet148/sqlca/v2" _ "github.com/go-sql-driver/mysql" "intent-system/pkg/dal/dao" "intent-system/pkg/dal/models" "strings" ) //var CasRule *casbin.Enforcer const DefaultCasbinModel = ` [request_definition] r = sub, obj, act [policy_definition] p = sub, obj, act [role_definition] g = _, _ [policy_effect] e = some(where (p.eft == allow)) [matchers] m = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && r.act == p.act || r.sub == "root" ` type CasbinOption struct { Model string DSN string } type CasbinRule struct { cas *casbin.Enforcer privilegeDAO *dao.PrivilegeDAO } func NewCasbinRule(opt CasbinOption) *CasbinRule { db, err := sqlca.NewEngine(opt.DSN) if err != nil { log.Panic("connect to database error [%s]", err.Error()) return nil } cas := &CasbinRule{ privilegeDAO: dao.NewPrivilegeDAO(db), cas: newCasbin(opt.DSN, opt.Model), } return cas.initPrivileges() } func newCasbin(strDSN, strModel string) (cas *casbin.Enforcer) { var err error if strings.HasPrefix(strDSN, "mysql://") { strDSN, err = sqlca.Url2MySql(strDSN) if err != nil { panic(err.Error()) } } log.Infof("DSN [%s]", strDSN) // 要使用自己定义的数据库,最后的true很重要.默认为false,使用缺省的数据库名casbin,不存在则创建,表不需要自己创建默认为casbin_rule a, err := xormadapter.NewAdapter("mysql", strDSN, true) if err != nil { log.Fatalf("error: model: %s", err) } if strModel == "" { strModel = DefaultCasbinModel } m, err := model.NewModelFromString(strModel) if err != nil { log.Fatalf("error: model: %s", err) } cas, err = casbin.NewEnforcer(m, a) if err != nil { log.Fatalf("error: model: %s", err) } //从DB加载策略 err = cas.LoadPolicy() if err != nil { log.Fatalf("casbin load policy error [%s]", err.Error()) return nil } return cas } // [][]string默认位数 const ( roleIndex = 0 pathIndex = 1 authIndex = 2 ) func (m *CasbinRule) initPrivileges() *CasbinRule { var err error for _, p := range TotalPrivileges() { _, err = m.privilegeDAO.Upsert(&models.PrivilegeDO{ Name: p.Name, Label: p.Label, Path: p.Path, Children: p.Children, IsInherent: true, Remark: "inherent privilege (DO NOT EDIT OR DELETE)", Deleted: false, }) if err != nil { log.Panic(err.Error()) } } return m } // 编辑权限(除账户和角色类其他菜单都可以增删改查) func (m *CasbinRule) EditPrivileges() (authorities []string) { return []string{ UserAccess, RoleAccess, NewsAccess, NewsAdd, NewsDelete, NewsEdit, QA_Access, QA_Add, QA_Delete, QA_Edit, SubAccess, SubAdd, SubEdit, TagAccess, TagAdd, TagDelete, TagEdit, CustomerAccess, } } // 普通管理账户权限(所有菜单均只有查看权限) func (m *CasbinRule) AccessPrivileges() (authorities []string) { return []string{ UserAccess, RoleAccess, NewsAccess, QA_Access, SubAccess, TagAccess, CustomerAccess, } } func (m *CasbinRule) TotalPrivileges() (authorities []string) { privileges := TotalPrivileges() for _, p := range privileges { as := recursiveAuthorities(p.Children) if len(as) != 0 { authorities = append(authorities, as...) } } return authorities } // 检查用户+URL+角色是否有访问权限 func (m *CasbinRule) Enforce(strUserName, strRequestURI string, privilege string) (ok bool, err error) { return m.cas.Enforce(strUserName, strRequestURI, string(privilege)) } // 添加角色权限 func (m *CasbinRule) AddRoleAuthority(role string, accessPath string, authority string) { _, err := m.cas.AddPolicy(role, accessPath, authority) if err != nil { log.Errorf("add role [%s] authority [%s] path [%s] error [%s]", role, authority, accessPath, err.Error()) return } } // 获取角色权限 func (m *CasbinRule) GetRoleAuthority(role string) (authority []string) { var authorityList = make([]string, 0) list := m.cas.GetPermissionsForUser(role) for _, vlist := range list { if len(vlist) > authIndex { authorityList = append(authorityList, vlist[authIndex]) } } return authorityList } // 角色权限继承 roleA 继承/获取 roleB权限 func (m *CasbinRule) InheritRoleAuthority(roleA, roleB string) { // 获取roleB权限 list := m.cas.GetPermissionsForUser(roleB) for _, listV := range list { if len(listV) >= authIndex { m.cas.AddPolicy(roleA, listV[pathIndex], listV[authIndex]) } } } // 角色更名时,用户继承新角色,并删除旧角色 func (m *CasbinRule) GetUsersForRole(role string) (users []string, err error) { return m.cas.GetUsersForRole(role) } // 角色更名时,用户继承新角色,并删除旧角色 func (m *CasbinRule) InheritUserRole(roleA, roleB string) { // 获取具有角色的用户 res, err := m.cas.GetUsersForRole(roleB) if err != nil { log.Errorf("get users for role:%s error:%s", roleB, err.Error()) return } for _, user := range res { m.AddUserRole(user, roleA) m.DeleteUserRole(user, roleB) } } // 删除角色权限 func (m *CasbinRule) DeleteRoleAuthority(role string, accessPath string, authority string) { if ok, _ := m.cas.RemovePolicy(role, accessPath, authority); !ok { fmt.Println("role authority doesn't exit!") } else { fmt.Println("role authority delete success") } } // 删除一个角色 func (m *CasbinRule) DeleteRole(role string) { m.cas.DeleteRole(role) } // 获取用户权限列表 func (m *CasbinRule) GetUserRoleList(userName string) (roleList []string) { roleList = make([]string, 0) // 获取用户角色 res, err := m.cas.GetRolesForUser(userName) if err != nil { log.Error(err.Error()) return roleList } for _, role := range res { // 获取角色权限 list := m.cas.GetPermissionsForUser(role) for _, vlist := range list { if len(vlist) >= authIndex { roleList = append(roleList, vlist[authIndex]) } } } return m.removeDuplicateElement(roleList) } // 为用户添加角色 func (m *CasbinRule) AddUserRole(userName string, role string) { if ok, _ := m.cas.AddRoleForUser(userName, role); !ok { log.Infof("role hadn't exit:%s", role) } else { log.Infof("add role success!") } } // 删除用户角色 func (m *CasbinRule) DeleteUserRole(userName, role string) { ok, _ := m.cas.DeleteRoleForUser(userName, role) if ok { log.Infof("delete role:%s for user:%s success", role, userName) } else { log.Infof("delete role:%s for user:%s failed!", role, userName) } } // 删除用户所有角色 func (m *CasbinRule) DeleteAllRoleForUser(userName string) { if ok, _ := m.cas.DeleteRolesForUser(userName); !ok { log.Infof("delete all user role failed:%s", userName) } else { log.Infof("delete all user role success!") } } // 删除一个用户 func (m *CasbinRule) DeleteUser(userName string) { m.cas.DeleteUser(userName) } // 权限列表去重 func (m *CasbinRule) removeDuplicateElement(authList []string) []string { result := make([]string, 0, len(authList)) temp := map[string]struct{}{} for _, item := range authList { if _, ok := temp[item]; !ok { temp[item] = struct{}{} result = append(result, item) } } return result } // 查询所有权限信息 func (m *CasbinRule) GetAllPrivileges() (privileges models.TreePrivilege) { return TotalPrivileges() } func (m *CasbinRule) GetPrivilegePath(auth string) (path string) { privileges := m.GetAllPrivileges() for _, p := range privileges { if p.Name == auth { return p.Path } path = recursiveSearchPath(auth, p.Children) if path != "" { return path } } return path } func recursiveSearchPath(auth string, children models.TreePrivilege) (path string) { for _, p := range children { if auth == p.Name { path = p.Path } else { if p.Children != nil { path = recursiveSearchPath(auth, p.Children) if path != "" { return path } } } } return path } func recursiveAuthorities(children models.TreePrivilege) (authorities []string) { for _, p := range children { if p.Name != "" { authorities = append(authorities, p.Name) } if p.Children != nil { as := recursiveAuthorities(p.Children) if len(as) != 0 { authorities = append(authorities, as...) } } } return }