Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

权限引擎之 casbin #102

Open
xizhibei opened this Issue Mar 24, 2019 · 0 comments

Comments

Projects
None yet
1 participant
@xizhibei
Copy link
Owner

xizhibei commented Mar 24, 2019

上次介绍了权限系统的设计后,这次我们来说说如何实现系统的实现。

复习一遍上次提到的内容,我们知道:

权限就是规定谁可以对什么资源进行什么样的操作。

那么,权限引擎就是根据这个原则来进行设计,于是,就引出了我们今天想介绍的工具:casbin

不过,今天想换种方式,如果我们自己要做个权限引擎,改如何实现呢?

假如我们自己实现

我们的需求

  1. 与具体业务场景无关,即所有的角色、资源以及操作都是抽象的;
  2. 适应任何权限模型,如 ACL,RBAC、ABAC;
  3. 管理相关的存储;

功能

我们理想中的情况就是:可以在中间件中,统一对用户进行鉴权,如果没有权限,中止继续访问,返回 HTTP status code 403,而如果有权限,则放行。

那么,再具体细化,就是这个权限引擎应该给我们提供至少以下几个接口:

  • 判断某个用户 ID 是否具有权限;
  • 管理用户角色,甚至角色组;
  • 管理角色的权限,即可以对那些资源进行什么样的操作;

实现

在这个模型中,有三种实体:

  • 角色:subject(用户可以与角色合并成为 subject,于是角色组也可以表示了);
  • 资源:object;
  • 操作:action;

然后,就是它们的关系,我们可以分为模型与规则,模型即 ACL、RBAC 等,而规则会涉及到具体业务对象,可以理解为模型相当于代码,而规则代表数据,比如在 RBAC 中,规定哪个用户会有什么角色,哪个角色可以对具体的资源进行什么操作等等。

好了,大致的需求就到此,因为往深了说就没完了,而这些简单的功能,我们都可以在自己的系统中去实现,毕竟如何运行都明白了。

只是,我们往往会做得跟业务比较耦合,因为一旦需要做个普适性的权限引擎,这点是完全不够的,你需要根据模型与规则,编写一套相应的规则引擎。所以,还是回到我们今天的主角,我们现在来看看 casbin 是如何实现的。

Casbin 的介绍

正如上面所说,它把模型称为 model,而规则称为 policy。

Model

一个具体的 RBAC model:

# Request definition
[request_definition]
r = sub, obj, act

# Policy definition
[policy_definition]
p = sub, obj, act

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

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

我们可以看到,Request definition 即为请求定义,代表了你可以传入什么样的参数来确定权限,而 Policy definition 代表了规则的组成,这两处也就是我上面说的,这个模型规定了,谁(sub)可以对什么资源(obj)进行什么操作(act)。

Policy effect 则表示什么样的规则可以被允许,e = some(where (p.eft == allow)) 这句就表示当前请求中包含的任何一个规则被允许的话,这个权限就会被允许,而反过来,假如是 e = !some(where (p.eft == deny)) 则表示,只要有一个规则被拒绝了,这个权限请求就会被拒绝,也就是说所有的规则都要被允许才能继续。

Matchers 表示请求与规则是如何起作用的,上面配置中的例子告诉我们,只有当请求与规则的 sub、obj、act 都相匹配的情况下,这条规则才会被批准。

Policy

与上面的模型相对应的规则,可以这样来写:

p, alice, data1, read
p, bob, data2, write

这两条记录就表示,alice 可以对 data1 进行读取,而 bob 可以对 data2 进行写入,那么接口的判断条件可以类似于这样的接口: isAllow('alice', 'data1', 'read')

在项目中使用

下面我们以 Golang 来简单说说如何在我们的项目中使用。

很简单:

e := casbin.NewEnforcer("path/to/model.conf", "path/to/policy.csv")

这句就是初始化了,然后:

if e.Enforce(sub, obj, act) {
    // 允许继续操作
} else {
    // 拒绝请求
}

是不是很简单呢?

在实际使用过程中,我们可以将这个步骤封装到一个中间件内统一处理,大致原理是将用户的 ID 与角色进行绑定,然后用 Enforce 来判断每次用户的请求是否被允许。

而当我们的系统是 Web 系统时,就更方便了,尤其是 RESTful 接口,每一个路径都是资源,而操作就是 GET, POST, PUT, DELETE 等。

对应例子可以利用 casbin 的内建函数来处理,将模型中的 matchers 改为:

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

对应的规则改为:

p, role1, /users/:id, GET
p, role2, /users/:id, POST
p, role3, /articles, .+

存储

我们可以看到,它默认的规则存储在 CSV 文件中,但是也可以存储在其它地方,比如各种数据库,具体可以去policy-storage查看。

其他

Casbin 目前支持多种语言,以及多种储存,更重要的上面我提到的几种权限模型它都支持,可以说是非常强大了。

假如是微服务,它也可以作为一个独立的权限微服务或者API网关的模块存在:https://casbin.org/docs/en/service。

核心代码其实是基于 github.com/Knetic/govaluate 来实现的,有兴趣的可以去看看

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.