beego利用casbin进行权限管理——第一节 起步、测试
beego利用casbin进行权限管理——第五节 策略更新(续)
EngineerCMS工程师知识(资料)管理系统的github地址。该系统正是充分利用了casbin进行树状目录赋权。
经过最后的冲刺,完成了EngineerCMS的权限管理:树状目录的赋权、修改和查看。
效果:
像在第三节中说的,赋权还是用单选吧,多选是方便了赋权,但是查询就很难结合了,比如多选几个角色,在树状目录中就无法反应权限了。
转入正题,树状目录的权限修改服务端:
//给角色赋项目目录的权限
//先删除角色对于这个项目的所有权限
func (c *RoleController) RolePermission() {
roleids := c.GetString("roleids")
rolearray := strings.Split(roleids, ",")
// beego.Info(rolearray)
permissionids := c.GetString("permissionids")
permissionarray := strings.Split(permissionids, ",")
// beego.Info(permissionarray)
sufids := c.GetString("sufids")
sufarray := strings.Split(sufids, ",")
treeids := c.GetString("treeids") //项目目录id,25001,25002
treearray := strings.Split(treeids, ",")
// beego.Info(treearray)
treenodeids := c.GetString("treenodeids") //项目目录的nodeid 0.0.0-0.0.1-0.1.0-0.1.0
treenodearray := strings.Split(treenodeids, ",")
projectid := c.GetString("projid")
var success bool
var nodeidint int
var projurl, action, suf1, suf string
var err error
//取出项目目录的顶级
var nodesid, nodesids []string
// beego.Info(len(treenodearray))
if len(treenodearray) > 1 {
nodesids, err = highest(treenodearray, nodesid, 0)
if err != nil {
beego.Error(err)
}
} else {
nodesids = []string{"0"} //append(nodesids, "0")
}
// beego.Info(nodesids)
//删除这些角色、项目id的全部权限
for _, v1 := range rolearray {
// var paths []beegoormadapter.CasbinRule
o := orm.NewOrm()
qs := o.QueryTable("casbin_rule")
_, err := qs.Filter("PType", "p").Filter("v0", "role_"+v1).Filter("v1__contains", "/"+projectid+"/").Delete()
if err != nil {
beego.Error(err)
}
}
// e.RemoveFilteredPolicy(1, "/onlyoffice/"+strconv.FormatInt(attachments[0].Id, 10))
e.LoadPolicy() //重载权限
for _, v1 := range rolearray {for _, v2 := range permissionarray {//定义读取、添加、修改、删除
switch v2 {
case "添加成果":
action = "POST"
suf = ".*"
case "编辑成果":
action = "PUT"
suf = ".*"
case "删除成果":
action = "DELETE"
suf = ".*"
case "读取成果":
action = "GET"
for i, v4 := range sufarray {
if v4 == "任意" {
suf = ".*"break}
else if v4 == "" { //用户没展开则读取不到table4的select
suf = "(?i:pdf)"
break
} else {
suf1 = "(?i:" + v4 + ")"
if i == 0 {
suf = suf1
} else {
suf = suf + "," + suf1
}
}
}
}
for _, v3 := range nodesids {
nodeidint, err = strconv.Atoi(v3)
if err != nil {
beego.Error(err)
}
//id转成64位
pidNum, err := strconv.ParseInt(treearray[nodeidint], 10, 64)
if err != nil {
beego.Error(err)
}
//根据projid取出路径
proj, err := m.GetProj(pidNum)
if err != nil {
beego.Error(err)
}
if proj.ParentIdPath == "" {
projurl = "/" + strconv.FormatInt(proj.Id, 10) + "/*"
} else {
projurl = "/" + strings.Replace(proj.ParentIdPath, "-", "/", -1) + "/" + treearray[nodeidint] + "/*"
}
beego.Info(v1)
sufarray := strings.Split(suf, ",")
for _, v5 := range sufarray {
success = e.AddPolicy("role_"+v1, projurl, action, v5) //来自casbin\management_api.go
//这里应该用AddPermissionForUser(),来自casbin\rbac_api.go
}
}
}
}if success == true {
c.Data["json"] = "ok"
} else {
c.Data["json"] = "wrong"}c.ServeJSON()
}
这里两点:一是数据库中树状目录的特点:
角色对于树状目录每一级下的对应扩展名的资源有读、写等权限,稍显复杂了点,但对于casbin不算啥。但是,要自己写删除语句_, err := qs.Filter("PType", "p").Filter("v0", "role_"+v1).Filter("v1__contains", "/"+projectid+"/").Delete()
用不了casbin的方法。
第二点,用自己的方法删除数据库后,必须用e.LoadPolicy() //重载权限,就是将数据库数据读入内存。因为只是删除了数据库,内存中的没有删除。然后才用casbin的方法添加新的数据,此时是添加到了内存,同时也添加到了数据库(问题:用casbin方法添加数据后,它内部是不是已经重载了数据库数据??答案是它内部没有loadpolicy)
其实,前端蛮难的,有几点。
1.bootstrap table多组表格的单选按钮问题。要每组定义成不同的select-item-name
<table id="table"
data-url="/admin/role/get/"
data-toggle="table"
data-striped="true"
data-toolbar="#toolbar1"
data-show-refresh="true"
data-show-toggle="true"
data-show-columns="true"
data-side-pagination="client"
data-pagination="true"
data-click-to-select="true"
data-page-size="5"
data-page-list="[5, 25, 50, All]"
data-search="false"
data-select-item-name="role"
>
2.本文第一张图中的表格内嵌套表格
/*数据json,"PDF":"","DWG":"","DOC":"","XLS":""*/
// 权限表
var json = [{"Id":"1","Title":"添加成果","Action":"POST"},
{"Id":"2","Title":"编辑成果","Action":"PUT"},
{"Id":"3","Title":"删除成果","Action":"DELETE"},
{"Id":"4","Title":"读取成果","Action":"GET"}];
var json1 = [{"Id":"5","Title":"任意","checked":true},
{"Id":"6","Title":"PDF"},
{"Id":"7","Title":"DWG"},
{"Id":"8","Title":"DOC"},
{"Id":"9","Title":"XLS"},
{"Id":"10","Title":"DGN"}];
/*初始化table数据*/
$(function(){
$("#table3").bootstrapTable({
data:json,
// onClickRow: function (row, $element) {
// alert( "选择了行Id为: " + row.Id );
// rowid=row.Id//全局变量
// $('#table1').bootstrapTable('refresh', {url:'/admincategory?pid='+row.Id});
// }
// onExpandRow: function (index, row, $Subdetail) {
// oInit.InitSubTable(index, row, $Subdetail);
// }
onExpandRow: function (index, row, $detail) {
expandTable(index, row,$detail);
}
});
});
function expandTable(index, row,$detail) {
var cur_table = $detail.html('<table id="table4"></table>').find('table');
if (index==3){
$(cur_table).bootstrapTable({
columns: [{
checkbox: true,
formatter: "stateFormatter"
}, {
field: 'Title',
title: '文件扩展名'
}],
data:json1,
})
}
}
3.嵌套表格中任意一行选择后,其他不可选
//文件扩展名选择
$(function(){
$("#table3").on("uncheck.bs.table",function(e,row,ele){
if (row.Id=="5"){
// for (var i=6;i<=10;i++){
// $('#table4').bootstrapTable('check',"1");
$('#table4 input').removeAttr("disabled"); //取消选择‘任意”后,其他变得可选
// }
}
})
$("#table3").on("check.bs.table",function(e,row,ele){
if (row.Id=="5"){
// for (var i=6;i<=10;i++){
// $('#table4').bootstrapTable('uncheckAll');
$('#table4 input').attr("disabled", true);//重新选择“任意”后,其他又变得不可选
$('[data-index="0"]').removeAttr("disabled");
$('#table4').bootstrapTable('check',"0");
// }
}
})
})
function stateFormatter(value, row, index) {
if (row.Id =="5") {
return {
// disabled: true,
checked: true
}
}else{
return {
disabled: true
// checked: true
}
}
if (row.checked === true) {
return {
checked: true
}
}
return value;
}