Casbin 是一个强大的、高效的开源访问控制框架,其权限管理机制支持多种访问控制模型。

通俗来讲就是一个权限管理的框架,把常见的权限管理集成在框架中,使用者只需要根据框架规范就可以很方便的实现相应的权限控制。

Casbin 支持的权限管理如下:

  • ACL (Access Control List, 访问控制列表)
  • 具有 超级用户 的 ACL
  • 没有用户的 ACL: 对于没有身份验证或用户登录的系统尤其有用。
  • 没有资源的 ACL: 某些场景可能只针对资源的类型, 而不是单个资源, 诸如  write-articleread-log 等权限。 它不控制对特定文章或日志的访问。
  • RBAC (基于角色的访问控制)
  • 支持资源角色的RBAC: 用户和资源可以同时具有角色 (或组)。
  • 支持域/租户的RBAC: 用户可以为不同的域/租户设置不同的角色集。
  • ABAC (基于属性的访问控制): 支持利用 resource.Owner 这种语法糖获取元素的属性。
  • RESTful: 支持路径, 如  /res/*/res/: id  和 HTTP 方法, 如  GETPOSTPUTDELETE
  • 拒绝优先: 支持允许和拒绝授权, 拒绝优先于允许。
  • 优先级: 策略规则按照先后次序确定优先级,类似于防火墙规则。

Model 概念

Model 相当于框架的配置文件,如我想在系统里有可能实现 是ALC 或者 RBAC ,应该如何告诉 Casbin 框架,我实现的是那种类型的权限控制呢?答案就是通过 Mdoel 来配置。

如果要掌握 Casbin 框架,那就需要对 Model 有一个比较深入的理解。接下来就讲解 Model 的一些语法。

request 定义

此处定义主要作用于验证时,应该验证哪些项,此处的配置名称和顺序是可以不固定的,你可以随意更改,但是需要与配置的其他部分配合上才可以,为了方便维护,建议按照官网的一些通用配置去配置。如上述配置,我这边就可以认为想要验证:用户角色,路由,方法。

定义方式如下(具体含义,请参考文档):

[request_definition]
r = sub, obj, act

Policy 定义

Policy (策略),主要是配置系统用户所拥有权限的规则,这里仅仅是规则的配置,数据是存在文件或数据库里的,存储的格式就是按照此配置进行存储的,存储是框架里处理好的,我们只需要调用相关方法即可。

如我想给张三加一条 /zhangsan get 的访问权限数据库就会存入下列信息 (数据库格式并非如此,为了方便讲解取了语义化的名字,实际操作中无需关心数据结构,casbin 已经在框架层面做了处理)

sub obj act
张三 /zhangsan get

当张三来请求 /zhangsan 资源的时候,我们可以通过前面配置的 request 与 这条记录进行对比,如果匹配的上就通过,匹配不上就提示无权访问的信息。匹配操作也是框架里有相关方法,我们只需要之道整个流程即可。

定义方式如下(具体含义,请参考文档):

[policy_definition]
 p = sub, obj, act

Policy effect 定义

Policy effect 主要用于一些多个匹配结果的处理,比如,我张三有两个 /zhangsan 的访问权限,且一个是允许访问,一个是不允许访问,那最终是否允许张三访问 /zhangsan 的资源,就是通过 Policy effect 来处理的

定义方式如下(具体含义,请参考文档):

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

匹配器(matchers)

我们前面定义了 request_definition和 policy_definition,他们们之间是如何进行匹配的?就是通过匹配器来确定的

定义方式如下(具体含义,请参考文档):

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

角色定义(role_definition)

角色定义是 RBAC 特有的一个配置项,用来定义角色的配置规则。

定义方式如下(具体含义,请参考文档):

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

这里需要结合 matchers 一起来说明,role_definition 可以看做定义了一个角色验证的函数,上述示例就是 g, 后面的两个 _ 则是对应函数传入的参数,这个 g 函数的使用就是在**匹配器(matchers)**中使用的。

上述配置即为,请求来了我需要拿 请求(r)中定义的 obj 和 act 去匹配策略(policy)中的 obj,act。 如果 r.obj==p.obj 并且 r.act == p.act 能匹配的到则说明有相关权限,请求放行,否则拒绝请求。

policy 如何存储

上个章节,我们只说到了 policy 的定义规则,那具体需要匹配的数据是用怎么样的方式来存储的呢。

policy 默认是通过 csv 文件存储, 可以通过 适配器  来扩展你自己的存储方式。

如何使用

Casbin使用配置文件来设置访问控制模式。

它有两个配置文件, model.confpolicy.csv 。 其中, model.conf 存储了访问模型, policy.csv 存储了特定的用户权限配置。 Casbin的使用非常精炼。 基本上,我们只需要一个主要结构:enforcer。 当构建这个结构时, model.confpolicy.csv 将被加载。换句话说,要新建一个Casbin执行器,你必须提供一个Model和一个Adapter

import (
    "log"

    "github.com/casbin/casbin/v2"
    "github.com/casbin/casbin/v2/model"
    xormadapter "github.com/casbin/xorm-adapter/v2"
    _ "github.com/go-sql-driver/mysql"
)

// 使用 MySQL 数据库初始化一个 Xorm 适配器
a, err := xormadapter.NewAdapter("mysql", "mysql_username:mysql_password@tcp(127.0.0.1:3306)/casbin")
if err != nil {
    log.Fatalf("error: adapter: %s", err)
}

m, err := model.NewModelFromString(`
[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
`)
if err != nil {
    log.Fatalf("error: model: %s", err)
}

e, err := casbin.NewEnforcer(m, a)
if err != nil {
    log.Fatalf("error: enforcer: %s", err)
}

你可能还会关心的一些东西

关于 RBAC

角色层次

我们都知道 RBAC 一般都会涉及到角色层次,如果  alice 具有 role1role1 具有 role2 ,则  alice  也将拥有  role2  并继承其权限。
角色层次有层数限制,默认为 10 也可以自己指定。

如何区分用户和角色

在RBAC中,Casbin不对用户和角色进行区分。 它们都被视为字符串

总结

这里基本上将 Casbin 一些基础概念和用法进行了说明,Casbin 作为一款流行的框架功能还是十分强大的。我们可以根据配置,组合出各种想要的权限控制。

在上述的介绍中,我们都只定理了 sub, obj, act 如果想增加对域名的控制应该如何做呢?文末会放一个验证域名的 RBAC 基础项目, 结合项目与本文,相信你会对 Casbin 有一个更加深入的理解。

示例项目

示例项目

参考连接: