基于Casbin实现ABAC

最近同事在研究Casbin的权限设计,咱们主要是考虑使用ABAC基于属性的访问控制,Casbin给的示例很少,因而本身写了几个示例。git

首先咱们看看提到ABAC时,通常描述以下:github

ABAC被一些人称为是权限系统设计的将来。测试

不一样于常见的将用户经过某种方式关联到权限的方式,ABAC则是经过动态计算一个或一组属性来是否知足某种条件来进行受权判断(能够编写简单的逻辑)。属性一般来讲分为四类:用户属性(如用户年龄),环境属性(如当前时间),操做属性(如读取)和对象属性(如一篇文章,又称资源属性),因此理论上可以实现很是灵活的权限控制,几乎能知足全部类型的需求。lua

例如规则:“容许全部班主任在上课时间自由进出校门”这条规则,其中,“班主任”是用户的角色属性,“上课时间”是环境属性,“进出”是操做属性,而“校门”就是对象属性了。为了实现便捷的规则设置和规则判断执行,ABAC一般有配置文件(XML、YAML等)或DSL配合规则解析引擎使用。spa

这里咱们就以这个班主任上课进出校门为例,看看在Casbin下是如何实现的:设计

首先,咱们定义用户环境和对象,操做咱们就直接用字符串code

type Person struct{
   Role string
   Name string
}
type Gate struct{
   Name string
}
type Env struct{
   Time time.Time
   Location string
}
func (env *Env) IsSchooltime() bool{
   return env.Time.Hour()>=8&&env.Time.Hour()<=18
}
接下来咱们根据这个权限描述,咱们能够写出以下的Casbin PERM模板:
[request_definition]
r = sub, obj, act, env

[policy_definition]
p = sub, obj,act

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

[matchers]
m = r.sub.Role=='Teacher' && r.obj.Name=='School Gate' && r.act in('In','Out') && r.env.Time.Hour >=8 && r.env.Time.Hour <= 18
由于咱们给Env对象定义了IsSchooltime方法,因此咱们也能够把目标写成以下,也是同样的效果:
[request_definition]
r = sub, obj, act, env

[policy_definition]
p = sub, obj,act

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

[matchers]
m = r.sub.Role=='Teacher' && r.obj.Name=='School Gate' && r.act in('In','Out') && r.env.IsSchooltime()
接下来咱们构造两我的,一个是学生Yun,一个是老师Devin,构造两个门,一个是工厂大门,一个是学校大门,操做的方法咱们就定义进门In和控制大门Control两个操做,环境上咱们定义一个是早上9点,一个是晚上23点。
完整代码以下:
func TestTeacherEnterSchoolGate() {
   p1 := Person{Role: "Student", Name: "Yun"}
   p2 := Person{Role: "Teacher", Name: "Devin"}
   persons := []Person{p1, p2}
   g1 := Gate{Name: "School Gate"}
   g2 := Gate{Name: "Factory Gate"}
   gates := []Gate{g1, g2}
   const modelText = `
[request_definition]
r = sub, obj, act, env

[policy_definition]
p = sub, obj,act

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

[matchers]
m = r.sub.Role=='Teacher' && r.obj.Name=='School Gate' && r.act in('In','Out') && r.env.Time.Hour >7 && r.env.Time.Hour <= 18
`
   //m = r.sub.Role=='Teacher' && r.obj.Name=='School Gate' && r.act in('In','Out') && r.env.IsSchooltime()
   m := model.Model{}

   m.LoadModelFromText(modelText)
   e := casbin.NewEnforcer(m)
   envs := []*Env{InitEnv(9), InitEnv(23)}
   for _, env := range envs {
      fmt.Println("\r\nTime:",env.Time.Local())
      for _, p := range persons {
         for _, g := range gates {
            pass := e.Enforce(p, g, "In", env)
            fmt.Println(p.Role, p.Name, "In", g.Name, pass)
            pass = e.Enforce(p, g, "Control", env)
            fmt.Println(p.Role,p.Name, "Control", g.Name, pass)
         }
      }
   }
}

func InitEnv(hour int) *Env{
   env:=&Env{}
   env.Time=time.Date(2019,8,20,hour,0,0,0,time.Local)
   return env
}
最后,输出结果以下:
Time: 2019-08-20 09:00:00 +0800 CST
Student Yun In School Gate false
Student Yun Control School Gate false
Student Yun In Factory Gate false
Student Yun Control Factory Gate false
Teacher Devin In School Gate true
Teacher Devin Control School Gate false
Teacher Devin In Factory Gate false
Teacher Devin Control Factory Gate false

Time: 2019-08-20 23:00:00 +0800 CST
Student Yun In School Gate false
Student Yun Control School Gate false
Student Yun In Factory Gate false
Student Yun Control Factory Gate false
Teacher Devin In School Gate false
Teacher Devin Control School Gate false
Teacher Devin In Factory Gate false
Teacher Devin Control Factory Gate false

咱们能够看到,在上课时间早上9点,学生是禁止进出校门,而只有老师Devin的进校门操做被经过。而到了晚上23点,老师Devin也不容许进校门了。对象

这里须要注意的是,在通常的模板中,是没有env这个环境变量的,我把它加到了request_definition的最后面写成r = sub, obj, act, env,同时e.Enforce(sub,obj,act,env)须要按顺序传入4个参数。blog

我还会对Casbin的ABAC进一步的研究,各测试用例会发布到https://github.com/studyzy/abactest 有兴趣的能够看看。资源

最后,关于Casbin采用的规则引擎为,https://github.com/Knetic/govaluate,编辑Matchers规则能够参考:https://github.com/Knetic/govaluate/blob/master/MANUAL.md

相关文章
相关标签/搜索