Gin框架入门-Casbin入门指南(ACL、RBAC、域内RBAC模型)

本文最后更新于:1 年前

一、Casbin概述

Casbin 是一个强大的、高效的开源访问控制框架,其权限管理机制支持多种访问控制模型。
Casbin参考文档链接:https://casbin.org/
github项目链接:https://github.com/casbin/casbin

Casbin 可以

  1. 支持自定义请求的格式,默认的请求格式为 **{subject, object, action}**。
  2. 具有访问控制模型model策略policy两个核心概念。
  3. 支持RBAC中的多层角色继承,不止主体可以有角色,资源也可以具有角色。
  4. 支持内置的超级用户 例如:root 或 administrator。超级用户可以执行任何操作而无需显式的权限声明。
  5. 支持多种内置的操作符,如 keyMatch,方便对路径式的资源进行管理,如 /foo/bar 可以映射到 /foo*

Casbin 不能

  1. 身份认证 authentication(即验证用户的用户名和密码),Casbin 只负责访问控制。应该有其他专门的组件负责身份认证,然后由 Casbin 进行访问控制,二者是相互配合的关系。
  2. 管理用户列表或角色列表。 Casbin 认为由项目自身来管理用户、角色列表更为合适, 用户通常有他们的密码,但是 Casbin 的设计思想并不是把它作为一个存储密码的容器。 而是存储RBAC方案中用户和角色之间的映射关系。

二、Casbin工作原理

在 Casbin 中, 访问控制模型被抽象为基于 PERM (Policy, Effect, Request, Matcher) 的一个文件。 因此,切换或升级项目的授权机制与修改配置一样简单。 您可以通过组合可用的模型来定制您自己的访问控制模型。 例如,您可以在一个model中结合RBAC角色和ABAC属性,并共享一组policy规则。

PERM模式由四个基础 (Policy, Effect, Request, Matcher) 组成,描述了资源与用户之间的关系。

三、Model语法

  • Model CONF 至少应包含四个部分: **[request_definition], [policy_definition], [policy_effect], [matchers]**。

  • 如果 model 使用 RBAC, 还需要添加 [role_definition] 部分。

  • Model CONF 文件可以包含注释。注释以 # 开头, # 会注释该行剩余部分。

1、Request定义

Request 定义请求参数。基本请求是一个元组对象,至少需要主题(访问实体)、对象(访问资源) 和动作(访问方式)

例如,一个请求可能长这样: r={sub,obj,act}
它实际上定义了我们应该提供访问控制匹配功能的参数名称和顺序。

[request_definition] 部分用于request的定义,它明确了 e.Enforce(…) 函数中参数的含义。

1
2
[request_definition]
r = sub, obj, act

sub, obj, act 表示经典三元组: 访问实体 (Subject),访问资源 (Object) 和访问方法 (Action)。 但是, 你可以自定义你自己的请求表单, 如果不需要指定特定资源,则可以这样定义 sub、act ,或者如果有两个访问实体, 则为 sub、sub2、obj、act

2、Policy定义

Policy 定义访问策略模式。事实上,它是在Policy规则文件中定义字段的名称和顺序。

例如: p={sub, obj, act} 或 p={sub, obj, act, eft}
注:如果未定义eft (policy result),则策略文件中的结果字段将不会被读取, 和匹配的策略结果将默认被允许 allow。

[policy_definition] 部分是对policy的定义,以下文的 model 配置为例:

1
2
3
[policy_definition]
p = sub, obj, act
p2 = sub, act
  • 这些是我们对policy规则的具体描述
    1
    2
    p, alice, data1, read
    p2, bob, write-all-objects

policy部分的每一行称之为一个策略规则, 每条策略规则通常以形如p, p2policy type开头。 如果存在多个policy定义,那么我们会根据前文提到的policy type与具体的某条定义匹配。 上面的policy的绑定关系将会在matcher中使用, 罗列如下:

1
2
(alice, data1, read) -> (p.sub, p.obj, p.act)
(bob, write-all-objects) -> (p2.sub, p2.act)

3、Matcher定义

Matcher 匹配请求 Request 和策略 Policy 的规则。

例如: m = r.sub == p.sub && r.act == p.act && r.obj == p.obj
这个匹配规则意味着如果请求Request的参数(访问实体,访问资源和访问方式)匹配, 可以在策略 Policy 中找到资源和方法,那么策略 Policy 结果(p.eft)便会返回。 策略的结果将保存在 p.eft 中。

[matchers] 是策略匹配程序的定义。匹配程序是表达式。它定义了如何根据请求评估策略规则。

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

上述匹配器是最简单的,这意味着请求中的主题、对象和行动应该与策略规则中的匹配。

您可以在匹配器中使用诸如 +, -, *, / 和逻辑操作员,例如 &&, ||, !

4、Policy effect定义

effect 可以被理解为一种模型,在这种模型中,对匹配结果再次作出逻辑组合判断。

例如: e = some (where (p.eft == allow))
这句话意味着,如果匹配的策略结果存在,并且 p.eft 是 allow 允许的,那么最终结果为 true。

[policy_effect] 是策略效果的定义。 它确定如果多项政策规则与请求相符,是否应批准访问请求。 例如,一项规则允许,另一项规则则加以拒绝。

1)some(where (p.eft == allow))

策略效果表示如果有任何匹配的策略规则 allow, 最终效果是 allow (aka allow-override). p.eft 是策略的效果,它可以 allowdeny。 它是可选的,默认值是 allow。 因为我们没有在上面指定它,所以它使用默认值。

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

2)some(where (p.eft == deny))

这意味着如果没有匹配的策略规则deny,最终效果是allow(又名拒绝覆盖)。some表示:如果存在一个匹配的策略规则。any表示:所有匹配的策略规则(此处未使用)。

1
2
[policy_effect]
e = !some(where (p.eft == deny))

3)some(where (p.eft == allow)) && !some(where (p.eft == deny))

表示至少有一个匹配的策略规则 allow,并且没有匹配的策略规则deny。因此,通过这种方式,允许和拒绝授权都受支持,并且拒绝覆盖。

1
2
[policy_effect]
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))

5、Role 定义

[role_definition] 是RBAC角色继承关系的定义。 Casbin 支持 RBAC 系统的多个实例, 例如, 用户可以具有角色及其继承关系, 资源也可以具有角色及其继承关系。 这两个 RBAC 系统不会互相干扰。

此部分是可选的。 如果在模型中不使用 RBAC 角色, 则省略此部分。

1
2
3
[role_definition]
g = _, _
g2 = _, _

g 是一个 RBAC系统, g2 是另一个 RBAC 系统。 _, _表示角色继承关系的前项和后项,即前项继承后项角色的权限。 一般来讲,如果您需要进行角色和用户的绑定,直接使用g 即可。 当您需要表示角色(或者组)与用户和资源的绑定关系时,可以使用g 和 g2 这样的表现形式。

在Casbin里,我们以policy表示中实际的用户角色映射关系 (或是资源-角色映射关系),例如:

1
2
p, data2_admin, data2, read
g, alice, data2_admin

这意味着 alice 是角色 data2_admin的一个成员。 alice 在这里可以是用户、资源或角色。 Cabin 只是将其识别为一个字符串。

接下来在matcher中,应该像下面的例子一样检查角色信息:

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

这意味着在请求 Request 中应该在policy中包含sub角色。
例如 r = {sub, dom, obj, act}

NOTE

  1. Casbin 只存储用户角色的映射关系。
  2. Cabin 没有验证用户是否是有效的用户,或者角色是一个有效的角色。 这应该通过认证来解决。
  3. RBAC 系统中的用户名称和角色名称不应相同。因为Casbin将用户名和角色识别为字符串, 所以当前语境下Casbin无法得出这个字面量到底指代用户 alice 还是角色 alice。 这时,使用明确的 role_alice ,问题便可迎刃而解。
  4. 假设A具有角色 BB 具有角色 C,并且 A 有角色 C。 这种传递性在当前版本会造成死循环。

四、ASL模型

在线编辑
您还可以使用在线编辑器 ( https://casbin.org/editor/ ) 在 Web 浏览器中编写您的 Casbin 模型和策略。

1、Model

Model规定了权限由 sub、obj、act三要素组成,只有在策略Policy列表中存在于请求Request完全相同的策略时,该请求才能通过。匹配器的结构通过 p.eft 获取, some(where (p.eft == allow)) 表示有任意一条 policy rule 满足, 则最终结果为 allow

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 请求
# sub ——> 想要访问资源的用户角色(Subject)——请求实体
# obj ——> 访问的资源(Object)
# act ——> 访问的方法(Action: get、post...)
[request_definition]
r = sub,obj,act


# 策略(.csv文件p的格式,定义的每一行为policy rule;p为policy rule的名字。)
[policy_definition]
p = sub,obj,act


# 策略效果
[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

2、Policy

Policy表示谁能对什么资源进行什么操作

1
2
p, linzy, data1, read
p, hhh, data2, write

linzy 对 资源 data1 有 read 权限
hhh 对 资源 data2 有 write 权限

3、Request

Request请求的策略

1
2
3
4
linzy, data1, read
linzy, data2, read
hhh, data2, write
hhh, data2, read

4、Enforcement Result

Enforcement Result返回的结果

1
2
3
4
true
false
true
false

五、RBAC模型

将某些具有特定模式的主题对象域/租户自动授予角色。RBAC 中的模式匹配函数可以帮助您做到这一点。

[role_definition] 是RBAC角色继承关系的定义。 Casbin 支持 RBAC 系统的多个实例, 例如, 用户可以具有角色及其继承关系, 资源也可以具有角色及其继承关系,****。

1、Model

Model规定了权限由 sub、obj、act三要素组成,只有在策略Policy列表中请求Request 或者 继承的角色里存在完全相同的策略时,该请求才能通过。匹配器的结构通过 p.eft 获取, some(where (p.eft == allow)) 表示有任意一条 policy rule 满足, 则最终结果为 allow

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#请求入参 (实体, 资源, 方法)
[request_definition]
r = sub, obj, act

#策略 (实体, 资源, 方法)
[policy_definition]
p = sub, obj, act

#按照角色权限,g = 用户, 角色
#用户继承角色的资源和方法
[role_definition]
g = _, _

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

#在权限表 p 中是否能找到用户和继承的角色的资源和方法
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act

2、Policy

Policy表示谁能对什么资源进行什么操作

1
2
3
4
5
6
7
p, linzy, data1, read
p, hhh, data2, write
p, data1_admin, data1, write
p, data2_admin, data2, read

g, linzy, data2_admin
g, hhh, data1_admin

linzy 对 资源 data1 和 data2 有 read 权限
hhh 对 资源 data2 和 data 1有 write 权限
data1_admin 对 资源 data1 有 write 权限
data2_admin 对 资源 data2 有 read 权限

linzy 继承了 角色data2_admin 的所有权限
hhh 继承了 角色 data1_admin 的所有权限

3、Request

Request请求的策略

1
2
3
4
5
linzy, data1, read
linzy, data2, write
hhh, data1, read
hhh, data2, write
data2_admin, data1, read

4、Enforcement Result

Enforcement Result返回的结果

1
2
3
4
5
true
false
false
true
false

六、域内RBAC模型

1、域租户的角色定义

在Casbin中的RBAC角色可以是全局或是基于特定于域的。 特定域的角色意味着当用户处于不同的域/租户群体时,用户所表现的角色也不尽相同。 这对于像云服务这样的大型系统非常有用,因为用户通常分属于不同的租户群体。

域/租户的角色定义应该类似于:

1
2
[role_definition]
g = _, _, _

第三个 _ 表示域/租户的名称, 此部分不应更改。

2、Model

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#请求入参 (实体, 域/租户, 资源, 方法)
[request_definition]
r = sub, dom, obj, act

#权限模型 (实体, 域/租户, 资源, 方法)
[policy_definition]
p = sub, dom, obj, act

# 域匹配规则 g = 用户, 角色, 域/租户
[role_definition]
g = _, _, _

#策略效果
[policy_effect]
e = some(where (p.eft == allow))

#在权限表 (p)中同一域/租户中的请求是否存在 相同的资源和方法
[matchers]
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act

3、Policy

Policy表示谁能对什么资源进行什么操作

1
2
3
4
5
6
7
p, admin, domain1, data1, read
p, admin, domain1, data1, write
p, admin, domain2, data2, read
p, admin, domain2, data2, write

g, linzy, admin, domain1
g, hhh, admin, domain2

admin 在 domain1 域中 对 资源data1 有 read 和 write 权限
admin 在 domain2 域中 对 资源data2 有 read 和 write 权限

用户 linzy 继承 admin 在 domain1 域中 的所有权限
用户 hhh 继承 admin 在 domain2 域中 的所有权限

3、Request

Request请求的策略

1
2
3
4
5
linzy, domain1, data1, read
linzy, domain1, data2, read
hhh, domain2, data1, read
hhh, domain2, data2, read
admin, domain1, data1, read

4、Enforcement Result

Enforcement Result返回的结果

1
2
3
4
5
true
false
false
true
true


Gin框架入门-Casbin入门指南(ACL、RBAC、域内RBAC模型)
https://gopherlinzy.github.io/2022/07/19/gin-Casbin1/
作者
孙禄毅
发布于
2022年7月19日
许可协议