354 lines
8.2 KiB
Go
354 lines
8.2 KiB
Go
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
|
||
}
|