当前位置: 首页 > 工具软件 > casbin > 使用案例 >

go语言casbin快速入门

黄流觞
2023-12-01

casbin快速入门


casbin将访问控制模型抽象到一个基于 PERM(Policy,Effect,Request,Matchers) 元模型的配置文件(模型文件)中

  • policy是策略或者说是规则的定义。它定义了具体的规则。

  • request是对访问请求的抽象,它与e.Enforce()函数的参数是一一对应的

  • matcher匹配器会将请求与定义的每个policy一一匹配,生成多个匹配结果。

  • effect根据对请求运用匹配器得出的所有结果进行汇总,来决定该请求是允许还是拒绝

下载依赖

下载依赖

go get github.com/casbin/casbin/v2

model文件(model.conf)

# 请求定义
[request_definiation]
r = sub,obj,act
# sub ——> 想要访问资源的用户角色(Subject)——请求实体
# obj ——> 访问的资源(Object)
# act ——> 访问的方法(Action: get、post...)


# 策略定义
# 策略(.csv文件p的格式,定义的每一行为policy rule;p,p2为policy rule的名字。)
[policy_definiation]
p = sub,obj,act
# p2 = sub,act 表示sub对所有资源都能执行act


# 组定义
[role_definiation]
g = _, _
# g = _,_定义了用户——角色,角色——角色的映射关系,前者是后者的成员,拥有后者的权限。
# _,_表示用户,角色/用户组


# 策略效果
[policy_effect]
e = some(where(p.eft = allow))
# 上面表示有任意一条 policy rule 满足, 则最终结果为 allow;p.eft它可以是allow或deny,它是可选的,默认是allow

# 匹配器
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act

# 上面模型文件规定了权限由sub,obj,act三要素组成,只有在策略列表中有和它完全相同的策略时,该请求才能通过。

policy文件(policy.csv)

p,zxp,data1,read
p,zhang,data2,write

代码实现

package main

import (
  "fmt"
  "log"

  "github.com/casbin/casbin/v2"
)

func check(e *casbin.Enforcer,sub,obj,act string){
	ok,_ := e.Enforcer(sub,obj,act)
	if ok {
    	fmt.Printf("%s CAN %s %s\n", sub, act, obj)
  	} else {
    	fmt.Printf("%s CANNOT %s %s\n", sub, act, obj)
  	}
}

func main() {
	//首先创建一个casbin.Enforcer对象,加载模型文件model.conf和策略文件policy.csv,调用其		Enforce方法来检查权限
  e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
  if err != nil {
    log.Fatalf("NewEnforecer failed:%v\n", err)
  }
  check(e, "zxp", "data1", "read")
  check(e, "zhang", "data2", "write")
  check(e, "zxp", "data1", "write")
  check(e, "zxp", "data2", "read")

测试结果:

zxp CAN read data1
zhang CAN write data2
zxp CANNOT write data1
zxp CANNOT read data2

超级管理员实现

[matchers]
e = r.sub == p.sub && r.obj == p.obj && r.act == p.act || r.sub == "root"

g = _, _的用法

g = _,__定义了用户——角色或角色——角色的映射关系,前者是后者的成员,拥有后者的权限。

model文件配置为

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

policy文件配置为

p, admin, data, read
p, admin, data, write
p, developer, data, read
g, zxp, admin
g, zhang, developer

admin对数据datareadwrite权限,而developer对数据data只有read权限。

zxp拥有admin的权限所以可读可写 zhang只能读

多个g _ , _

model文件配置改为:

[role_definition]
g=_,_
g2=_,_

[matchers]
m = g(r.sub, p.sub) && g2(r.obj, p.obj) && r.act == p.act
# 只改这两个,其他不变

policy文件举例如下:

p, admin, data1, read
p, admin, data1, write
p, admin, data2, read
p, admin, data2, write
p, developer, data2, read
p, developer, data2, write
p, developer, data1, read
g, zxp, admin
g, zhang, developer
g2, data1.data, data1
g2, data2.data, data2

zxp属于admin所以对data1data2可读可写

zhang属于developer所以对data1可读。对data2可读可写

data1.data属于data1,所以zxp可读可写,zhangdata1.data可读

data2.data属于data2,所以zhang可读可写

多层角色

model文件不用修改

policy文件举例如下:

p, senior, data, write
p, developer, data, read
g, zxp, senior
g, senior, developer
g, zhang, developer

seniordatawrite权限

developer只有read权限,同时senior也是developer(前者拥有后者的权限),所以senior也继承其read权限。

zxp可读可写data

zhang可读data

domain领域

model文件修改如下

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

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

[role_definition]
g = _,_,_
# g2 = _,_,_ 表示用户, 角色/用户组, 域(也就是租户)


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

policy文件举例如下:

p, admin, dom1, data1, read
p, admin, dom2, data2, read
g, zxp, admin, dom1

dom1中,只有admin可以读取数据data1

dom2中,只有admin可以读取数据data2

zxpdata1中是admin,但是在data2中不是。

代码实现

func check(e *casbin.Enforcer, sub, domain, obj, act string) {
  ok, _ := e.Enforce(sub, domain, obj, act)
  if ok {
    fmt.Printf("%s CAN %s %s in %s\n", sub, act, obj, domain)
  } else {
    fmt.Printf("%s CANNOT %s %s in %s\n", sub, act, obj, domain)
  }
}

func main() {
  e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
  if err != nil {
    log.Fatalf("NewEnforecer failed:%v\n", err)
  }

  check(e, "dajun", "dom1", "data1", "read")
  check(e, "dajun", "dom2", "data2", "read")
}

动态控制可读可写

根据时间控制

model文件修改如下

[matchers]
m = r.sub.Hour >= 5 && r.sub.Hour < 20 || r.sub.Name == r.obj.Owner> 

注意:该模式下不需要policy文件配置

代码实现

type Object struct {
  Name  string
  Owner string
}

type Subject struct {
  Name string
  Hour int
}

func check(e *casbin.Enforcer, sub Subject, obj Object, act string) {
  ok, _ := e.Enforce(sub, obj, act)
  if ok {
    fmt.Printf("%s CAN %s %s at %d:00\n", sub.Name, act, obj.Name, sub.Hour)
  } else {
    fmt.Printf("%s CANNOT %s %s at %d:00\n", sub.Name, act, obj.Name, sub.Hour)
  }
}

func main() {
  e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
  if err != nil {
    log.Fatalf("NewEnforecer failed:%v\n", err)
  }

  //r.sub.Hour < 18 || r.sub.Name == r.obj.Owner 这两个满足一个就可读
  o := Object{"data", "zxp"}
    
    
  s1 := Subject{"zxp", 10}
  check(e, s1, o, "read")//可读

  s2 := Subject{"zhang", 10}
  check(e, s2, o, "read")//可读

  s4 := Subject{"zhang", 20}
  check(e, s4, o, "read")//不可读
    

模式存储

动态初始化model文件(代码内实现model)

func check(e *casbin.Enforcer,sub,obj,act string){
	ok,_ := e.Enforcer(sub,obj,act)
	if ok {
    	fmt.Printf("%s CAN %s %s\n", sub, act, obj)
  	} else {
    	fmt.Printf("%s CANNOT %s %s\n", sub, act, obj)
  	}
}


//第一种写法
func main() {
  m := model.NewModel()
  m.AddDef("r", "r", "sub, obj, act")
  m.AddDef("p", "p", "sub, obj, act")
  m.AddDef("e", "e", "some(where (p.eft == allow))")
  m.AddDef("m", "m", "r.sub == g.sub && r.obj == p.obj && r.act == p.act")

  a := fileadapter.NewAdapter("./policy.csv")
  e, err := casbin.NewEnforcer(m, a)
  if err != nil {
    log.Fatalf("NewEnforecer failed:%v\n", err)
  }

  check(e, "zxp", "data1", "read")
  check(e, "zhang", "data2", "write")
  check(e, "zxp", "data1", "write")
  check(e, "zxp", "data2", "read")
}

//第二种写法
func main() {
  text := `
  [request_definition]
  r = sub, obj, act

  [policy_definition]
  p = sub, obj, act

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

  [matchers]
  m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
  `

  m, _ := model.NewModelFromString(text)
  a := fileadapter.NewAdapter("./policy.csv")
  e, _ := casbin.NewEnforcer(m, a)
}

策略储存policy.csv实际运用

使用Gorm Adapter。先连接到数据库,执行下面的SQL

CREATE DATABASE IF NOT EXISTS casbin;

USE casbin;

CREATE TABLE IF NOT EXISTS casbin_rule (
  p_type VARCHAR(100) NOT NULL,
  s0 VARCHAR(100),
  s1 VARCHAR(100),
  s2 VARCHAR(100)
);

INSERT INTO casbin_rule VALUES
('p', zxp', 'data1', 'read', '', '', ''),
('p', 'zhang', 'data2', 'write', '', '', ''); 

代码实现

func check(e *casbin.Enforcer, sub, obj, act string) {
  ok, _ := e.Enforce(sub, obj, act)
  if ok {
    fmt.Printf("%s CAN %s %s\n", sub, act, obj)
  } else {
    fmt.Printf("%s CANNOT %s %s\n", sub, act, obj)
  }
}

func main() {
  a, _ := gormadapter.NewAdapter("mysql", "root:12345@tcp(127.0.0.1:3306)/")
  e, _ := casbin.NewEnforcer("./model.conf", a)

  check(e, "zxp", "data1", "read")//可读
  check(e, "zhang", "data2", "write")//可写
 
}
 类似资料: