plugai_updsrv/pkg/privilege/casbin.go

354 lines
8.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}