首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >beego利用casbin进行权限管理——第二节 策略存储

beego利用casbin进行权限管理——第二节 策略存储

作者头像
hotqin888
发布2018-09-11 15:05:11
1.1K0
发布2018-09-11 15:05:11
举报
文章被收录于专栏:hotqin888的专栏hotqin888的专栏

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1334509

上一节讲到修改casbin目录下beego-orm-adapter里的adapter.go,这里要继续修改一下,否则会把数据库冲掉。

接下来进行用户的角色分配。

代码如下,其实就是生成策略——把用户对应角色写入数据库casbin_rule

//添加用户角色
//先删除用户所有角色
func (c *RoleController) UserRole() {
	//要支持批量分配角色,循环用户id
	uid := c.GetString("uid") 
	//先删除用户的权限
	e.DeleteRolesForUser(uid) //下节介绍这个
	//再添加,如果没有选择,相当于删除了全部角色
	ids := c.GetString("ids") //roleid
	if ids != "" {
		array := strings.Split(ids, ",")
		for _, v1 := range array {
			e.AddGroupingPolicy(uid, "role_"+v1) //management_api.go
			//应该用AddRoleForUser()//rbac_api.go
		}
		// a.SavePolicy(e.GetModel())//autosave默认是true
		// 	[{0 p 12 1    } {0 g 8 1    } {0 g 7 1
		//    } {0 g 7 2    } {0 g 5 1    } {0 g 5 2    }]
		// lines := [7][4]string{{"0", "p", "100", "1"}, {"0", "p", "101", "1"}}
		// _, err := a.o.InsertMulti(len(lines), lines)
		// return err
	}
	c.Data["json"] = "ok"
	c.ServeJSON()
}

当然,前提是你先定义了角色。

数据库中的样子是这样的:

接下来是给角色赋予对某某目录下(v1/v2/v3/*)资源的各种权限。

conf目录下的rbac_model.conf如下

[request_definition]
r = sub, obj, act, suf 

[policy_definition]
p = sub, obj, act, suf

[role_definition]
g = _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && regexMatch(r.suf, p.suf) && r.act == p.act

接下来给角色赋予项目目录下资源的请求权限,

代码:

//给角色赋项目目录的权限
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
	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, ",")
	// beego.Info(treenodearray)
	// treeids := c.GetString("tree")
	//json字符串解析到结构体,以便进行追加
	// var tree []Tree
	// err := json.Unmarshal([]byte(treeids), &tree)
	// if err != nil {
	// 	beego.Error(err)
	// }
	var success bool
	var nodeidint int
	var projurl, action, suf string
	var err error
	//取出项目目录的顶级
	var nodesid, nodesids []string
	if len(treenodearray) > 1 {
		nodesids, err = highest(treenodearray, nodesid, 0)
		if err != nil {
			beego.Error(err)
		}
	}
	// beego.Info(nodesids)
	for _, v1 := range rolearray {
		for _, v2 := range permissionarray {
			//定义读取、添加、修改、删除
			switch v2 {
			case "添加成果":
				action = "POST"
				suf = ".*"
			case "编辑成果":
				action = "UPDATE"
				suf = ".*"
			case "删除成果":
				action = "DELETE"
				suf = ".*"
			case "读取成果":
				action = "GET"
				for _, v4 := range sufarray {
					if v4 == "任意" {
						suf = ".*"
						break
					} else if v4 == "" { //用户没展开则读取不到table4的select
						suf = "(?i:pdf)"
					} else {
						suf = "(?i:" + v4 + ")"
					}
				}
			}

			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] + "/*"
				}
				success = e.AddPolicy(v1, projurl, action, suf)
			}
		}
	}
	if success == true {
		c.Data["json"] = "ok"
	} else {
		c.Data["json"] = "wrong"
	}
	c.ServeJSON()
}

//迭代查出最高级的树状目录
func highest(nodeid []string, nodesid []string, i int) (nodesid1 []string, err error) {
	if i == 0 {
		nodesid = append(nodesid, "0")
	}
	var i1 int
	for i1 = i; i1 < len(nodeid)-1; i1++ {
		matched, err := regexp.MatchString("(?i:"+nodeid[i]+")", nodeid[i1+1])
		// fmt.Println(matched)
		if err != nil {
			beego.Error(err)
		}
		if !matched {
			i = i1 + 1
			nodesid = append(nodesid, strconv.Itoa(i1+1))
			break
		} else {
			if i == len(nodeid)-2 {
				return nodesid, err
			}
		}
	}
	if i1 < len(nodeid)-1 {
		nodesid, err = highest(nodeid, nodesid, i)
	}
	return nodesid, err
}

上面求树状目录最高级的目的是:我们选中某一级目录,其下级自动选中了,这些目录id传递到服务端后,我们只需要往策略里存入最高级的就行了,然后用keymatch匹配路由即可。比如,策略里运行访问v1/v2/*,那么,你访问v1/v2/v3/*也是可以的了。

查出用户的权限:

func (c *RoleController) Get() {
	id := c.Ctx.Input.Param(":id")
	c.Data["Id"] = id
	c.Data["Ip"] = c.Ctx.Input.IP()
	// if id == "" { //如果id为空,则查询
	roles, err := m.GetRoles()
	if err != nil {
		beego.Error(err)
	}

	if id != "" {
		//查出用户的角色,处于勾选状态
		userroles := e.GetRolesForUser(id)
		userrole := make([]Userrole, 0)
		var level string
		level = "2"
		for _, v1 := range roles {
			for _, v2 := range userroles {
				ridNum, err := strconv.ParseInt(v2, 10, 64)
				if err != nil {
					beego.Error(err)
				}
				if ridNum == v1.Id {
					level = "1"
				}
			}
			aa := make([]Userrole, 1)
			aa[0].Id = v1.Id
			aa[0].Rolename = v1.Rolename
			aa[0].Rolenumber = v1.Rolenumber
			aa[0].Level = level
			userrole = append(userrole, aa...)
			aa = make([]Userrole, 0)
			level = "2"
		}
		c.Data["json"] = userrole
		c.ServeJSON()
	}
	c.Data["json"] = roles
	c.ServeJSON()
}

 其他说明:

1.用户id和角色id重复问题。因为p策略可能对应的是user,也可能对应的role,所以当2者id相同的时候,就分不清是用户还是角色了。所以要给角色id前加role_字样。

(我这里存入的是用户id对应角色id,然后是角色对应的路由和请求权限,问题来了,当用户id和角色id相同的时候,即时这个用户不在角色里,这个用户直接具有了请求的权限,因为casbin不分辨用户和和角色。解决方案,是将角色id加上_role,比如1_role,在服务端再做处理。)

这里讲用户和角色重名的问题。

// Create Role and User 

// Casbin only stores the user-role mapping. 

 // Do not use the same name for a user and a role inside a RBAC system, 

 // because Casbin recognizes users and roles as strings, and there's no way for 

 // Casbin to know whether you are specifying user alice or role alice. 

 // You can simply solve it by using role_alice. 

https://github.com/luk4z7/middleware-acl/blob/9764e0c0bcc1804272921c34da0148caa2448d63/src/middleware/service/role/role.go#L19-L22

2.只需要addpolicy(实时存入map)就行了,而不需要savepolicy(存入数据库),因为自动存入数据库了。这里讲自动存入数据库,好处是避免了重复存储。

https://github.com/casbin/casbin/wiki/AutoSave

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017年11月18日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档