访问控制模型 DAC MAC RBAC ABAC
https://en.wikipedia.org/wiki/Access_control#Access_control_models
Access control models
Access to accounts can be enforced through many types of controls.[21]
- Attribute-based Access Control (ABAC)
An access control paradigm whereby access rights are granted to users through the use of policies which evaluate attributes (user attributes, resource attributes and environment conditions)[22] - Discretionary Access Control (DAC)
In DAC, the data owner determines who can access specific resources. For example, a system administrator may create a hierarchy of files to be accessed based on certain permissions. - Graph-based Access Control (GBAC)
Compared to other approaches like RBAC or ABAC, the main difference is that in GBAC access rights are defined using an organizational query language instead of total enumeration. - History-Based Access Control (HBAC)
Access is granted or declined based on the real-time evaluation of a history of activities of the inquiring party, e.g. behavior, time between requests, content of requests.[23] For example, the access to a certain service or data source can be granted or declined on the personal behavior, e.g. the request interval exceeds one query per second. - History-of-Presence Based Access Control (HPBAC)
Access control to resources is defined in terms of presence policies that need to be satisfied by presence records stored by the requestor. Policies are usually written in terms of frequency, spread and regularity. An example policy would be "The requestor has made k separate visitations, all within last week, and no two consecutive visitations are apart by more than T hours."[24] - Identity-Based Access Control (IBAC)
Using this network administrators can more effectively manage activity and access based on individual needs.[25] - Lattice-Based Access Control (LBAC)
A lattice is used to define the levels of security that an object may have and that a subject may have access to. The subject is only allowed to access an object if the security level of the subject is greater than or equal to that of the object. - Mandatory Access Control (MAC)
In MAC, users do not have much freedom to determine who has access to their files. For example, security clearance of users and classification of data (as confidential, secret or top secret) are used as security labels to define the level of trust. - Organization-Based Access Control (OrBAC)
OrBAC model allows the policy designer to define a security policy independently of the implementation[26] - Role-Based Access Control (RBAC)
RBAC allows access based on the job title. RBAC largely eliminates discretion when providing access to objects. For example, a human resources specialist should not have permissions to create network accounts; this should be a role reserved for network administrators. - Rule-Based Access Control (RAC)
RAC method, also referred to as Rule-Based Role-Based Access Control (RB-RBAC), is largely context based. Example of this would be allowing students to use labs only during a certain time of day; it is the combination of students' RBAC-based information system access control with the time-based lab access rules. - Responsibility Based Access Control
Information is accessed based on the responsibilities assigned to an actor or a business role[27]
访问控制有很多模型,比如:
- 自主存取控制(英语:Discretionary access control)
- 强制访问控制(英语:Mandatory access control)
- 角色访问控制(英语:Role-based access control)
- 属性访问控制(英语:Attribute-based access control)
- 识别访问控制(英语:Identity-based access control)
概述 | Casbin https://casbin.org/zh/docs/overview
Casbin 是一个强大和高效的开放源码访问控制库,它支持各种 访问控制模型 以强制全面执行授权。
执行一套规则与列出下述问题一样简单。 对象和所需的 在 策略 文件中允许的动作(或根据您的需要提供任何其他格式)。 这是Casbin使用的所有流的同义词。 开发者/管理员有 完全控制布局, 通过 模型 文件设置的执行和授权条件 。 Casbin提供了一个执行者 根据提供给执行者的策略和模型文件验证传入的请求。
Casbin 是什么?
Casbin 是一个授权库,在我们希望特定用户访问特定的 对象
或实体的流程中可以使用 主题
访问类型,例如 动作
可以是 读取, 写入, 删除 或开发者设置的任何其他动作。 这是Casbin最广泛的使用,它叫做"标准" 或经典 { subject, object, action }
流程。
Casbin能够处理除标准流量以外的许多复杂的许可使用者。 可以添加 角色 (RBAC), 属性 (ABAC) 等。
Casbin 可以:
- Enforce the policy in the classic
{ subject, object, action }
form or a customized form as you defined. 支持允许和拒绝授权。 - 具有访问控制模型model和策略policy两个核心概念。
- 支持RBAC中的多层角色继承,不止主体可以有角色,资源也可以具有角色。
- 支持内置超级用户,如
root
或administrator
。 超级用户可以在没有明确权限的情况下做任何事情。 - 支持规则匹配的多个内置运营商。 For example,
keyMatch
can map a resource key/foo/bar
to the pattern/foo*
.
Casbin不可以做什么
- 身份认证 authentication(即验证用户的用户名和密码),Casbin 只负责访问控制。应该有其他专门的组件负责身份认证,然后由 Casbin 进行访问控制,二者是相互配合的关系。
- 管理用户列表或角色列表。
该项目更容易管理他们的用户、角色或密码列表。 用户通常有他们的密码,但是 Casbin 的设计思想并不是把它作为一个存储密码的容器。 而是存储RBAC方案中用户和角色之间的映射关系。
什么是ABAC模式?
ABAC是 基于属性的访问控制
,可以使用主体、客体或动作的属性,而不是字符串本身来控制访问。 您之前可能就已经听过 XACML ,是一个复杂的 ABAC 访问控制语言。 与XACML相比,Casbin的ABAC非常简单: 在ABAC中,可以使用struct(或基于编程语言的类实例) 而不是字符串来表示模型元素。
Casbin是一个强大的、高效的开源访问控制框架,其权限管理机制支持多种访问控制模型。
开始使用 · Casbin https://casbin.org/docs/zh-CN/get-started
权限系统设计模型分析(DAC,MAC,RBAC,ABAC) - 简书 https://www.jianshu.com/p/ce0944b4a903
RBAC
模型对于实现比较规则的、相对静态的权限管理非常有用。但是对于特殊的、动态的需求,RBAC
就显得有点力不从心了。例如,我们在不同的时间段对数据data
实现不同的权限控制。正常工作时间9:00-18:00
所有人都可以读写data
,其他时间只有数据所有者能读写。
Go 每日一库之 casbin - 掘金 https://juejin.cn/post/6844904191257739277
简介
权限管理在几乎每个系统中都是必备的模块。如果项目开发每次都要实现一次权限管理,无疑会浪费开发时间,增加开发成本。因此,casbin
库出现了。casbin
是一个强大、高效的访问控制库。支持常用的多种访问控制模型,如ACL/RBAC/ABAC
等。可以实现灵活的访问权限控制。同时,casbin
支持多种编程语言,Go/Java/Node/PHP/Python/.NET/Rust
。我们只需要一次学习,多处运用。
快速使用
我们依然使用 Go Module 编写代码,先初始化:
$ mkdir casbin && cd casbin
$ go mod init github.com/darjun/go-daily-lib/casbin
复制代码
然后安装casbin
,目前是v2
版本:
$ go get github.com/casbin/casbin/v2
复制代码
权限实际上就是控制谁能对什么资源进行什么操作。casbin
将访问控制模型抽象到一个基于 PERM(Policy,Effect,Request,Matchers) 元模型的配置文件(模型文件)中。因此切换或更新授权机制只需要简单地修改配置文件。
policy
是策略或者说是规则的定义。它定义了具体的规则。
request
是对访问请求的抽象,它与e.Enforce()
函数的参数是一一对应的
matcher
匹配器会将请求与定义的每个policy
一一匹配,生成多个匹配结果。
effect
根据对请求运用匹配器得出的所有结果进行汇总,来决定该请求是允许还是拒绝。
下面这张图很好地描绘了这个过程:
我们首先编写模型文件:
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
[policy_effect]
e = some(where (p.eft == allow))
复制代码
上面模型文件规定了权限由sub,obj,act
三要素组成,只有在策略列表中有和它完全相同的策略时,该请求才能通过。匹配器的结果可以通过p.eft
获取,some(where (p.eft == allow))
表示只要有一条策略允许即可。
然后我们策略文件(即谁能对什么资源进行什么操作):
p, dajun, data1, read
p, lizi, data2, write
复制代码
上面policy.csv
文件的两行内容表示dajun
对数据data1
有read
权限,lizi
对数据data2
有write
权限。
接下来就是使用的代码:
package main
import (
"fmt"
"log"
"github.com/casbin/casbin/v2"
)
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() {
e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
if err != nil {
log.Fatalf("NewEnforecer failed:%v\n", err)
}
check(e, "dajun", "data1", "read")
check(e, "lizi", "data2", "write")
check(e, "dajun", "data1", "write")
check(e, "dajun", "data2", "read")
}
复制代码
代码其实不复杂。首先创建一个casbin.Enforcer
对象,加载模型文件model.conf
和策略文件policy.csv
,调用其Enforce
方法来检查权限。运行程序:
$ go run main.go
dajun CAN read data1
lizi CAN write data2
dajun CANNOT write data1
dajun CANNOT read data2
复制代码
请求必须完全匹配某条策略才能通过。("dajun", "data1", "read")
匹配p, dajun, data1, read
,("lizi", "data2", "write")
匹配p, lizi, data2, write
,所以前两个检查通过。第 3 个因为"dajun"
没有对data1
的write
权限,第 4 个因为dajun
对data2
没有read
权限,所以检查都不能通过。输出结果符合预期。
sub/obj/act
依次对应传给Enforce
方法的三个参数。实际上这里的sub/obj/act
和read/write/data1/data2
是我自己随便取的,你完全可以使用其它的名字,只要能前后一致即可。
上面例子中实现的就是ACL
(access-control-list,访问控制列表)。ACL
显示定义了每个主体对每个资源的权限情况,未定义的就没有权限。我们还可以加上超级管理员,超级管理员可以进行任何操作。假设超级管理员为root
,我们只需要修改匹配器:
[matchers]
e = r.sub == p.sub && r.obj == p.obj && r.act == p.act || r.sub == "root"
复制代码
只要访问主体是root
一律放行。
验证:
func main() {
e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
if err != nil {
log.Fatalf("NewEnforecer failed:%v\n", err)
}
check(e, "root", "data1", "read")
check(e, "root", "data2", "write")
check(e, "root", "data1", "execute")
check(e, "root", "data3", "rwx")
}
复制代码
因为sub = "root"
时,匹配器一定能通过,运行结果:
$ go run main.go
root CAN read data1
root CAN write data2
root CAN execute data1
root CAN rwx data3
复制代码
RBAC 模型
ACL
模型在用户和资源都比较少的情况下没什么问题,但是用户和资源量一大,ACL
就会变得异常繁琐。想象一下,每次新增一个用户,都要把他需要的权限重新设置一遍是多么地痛苦。RBAC
(role-based-access-control)模型通过引入角色(role
)这个中间层来解决这个问题。每个用户都属于一个角色,例如开发者、管理员、运维等,每个角色都有其特定的权限,权限的增加和删除都通过角色来进行。这样新增一个用户时,我们只需要给他指派一个角色,他就能拥有该角色的所有权限。修改角色的权限时,属于这个角色的用户权限就会相应的修改。
在casbin
中使用RBAC
模型需要在模型文件中添加role_definition
模块:
[role_definition]
g = _, _
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
复制代码
g = _,_
定义了用户——角色,角色——角色的映射关系,前者是后者的成员,拥有后者的权限。然后在匹配器中,我们不需要判断r.sub
与p.sub
完全相等,只需要使用g(r.sub, p.sub)
来判断请求主体r.sub
是否属于p.sub
这个角色即可。最后我们修改策略文件添加用户——角色定义:
p, admin, data, read
p, admin, data, write
p, developer, data, read
g, dajun, admin
g, lizi, developer
复制代码
上面的policy.csv
文件规定了,dajun
属于admin
管理员,lizi
属于developer
开发者,使用g
来定义这层关系。另外admin
对数据data
用read
和write
权限,而developer
对数据data
只有read
权限。
package main
import (
"fmt"
"log"
"github.com/casbin/casbin/v2"
)
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() {
e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
if err != nil {
log.Fatalf("NewEnforecer failed:%v\n", err)
}
check(e, "dajun", "data", "read")
check(e, "dajun", "data", "write")
check(e, "lizi", "data", "read")
check(e, "lizi", "data", "write")
}
复制代码
很显然lizi
所属角色没有write
权限:
dajun CAN read data
dajun CAN write data
lizi CAN read data
lizi CANNOT write data
复制代码
多个RBAC
casbin
支持同时存在多个RBAC
系统,即用户和资源都有角色:
[role_definition]
g=_,_
g2=_,_
[matchers]
m = g(r.sub, p.sub) && g2(r.obj, p.obj) && r.act == p.act
复制代码
上面的模型文件定义了两个RBAC
系统g
和g2
,我们在匹配器中使用g(r.sub, p.sub)
判断请求主体属于特定组,g2(r.obj, p.obj)
判断请求资源属于特定组,且操作一致即可放行。
策略文件:
p, admin, prod, read
p, admin, prod, write
p, admin, dev, read
p, admin, dev, write
p, developer, dev, read
p, developer, dev, write
p, developer, prod, read
g, dajun, admin
g, lizi, developer
g2, prod.data, prod
g2, dev.data, dev
复制代码
先看角色关系,即最后 4 行,dajun
属于admin
角色,lizi
属于developer
角色,prod.data
属于生产资源prod
角色,dev.data
属于开发资源dev
角色。admin
角色拥有对prod
和dev
类资源的读写权限,developer
只能拥有对dev
的读写权限和prod
的读权限。
check(e, "dajun", "prod.data", "read")
check(e, "dajun", "prod.data", "write")
check(e, "lizi", "dev.data", "read")
check(e, "lizi", "dev.data", "write")
check(e, "lizi", "prod.data", "write")
复制代码
第一个函数中e.Enforce()
方法在实际执行的时候先获取dajun
所属角色admin
,再获取prod.data
所属角色prod
,根据文件中第一行p, admin, prod, read
允许请求。最后一个函数中lizi
属于角色developer
,而prod.data
属于角色prod
,所有策略都不允许,故该请求被拒绝:
dajun CAN read prod.data
dajun CAN write prod.data
lizi CAN read dev.data
lizi CAN write dev.data
lizi CANNOT write prod.data
复制代码
多层角色
casbin
还能为角色定义所属角色,从而实现多层角色关系,这种权限关系是可以传递的。例如dajun
属于高级开发者senior
,seinor
属于开发者,那么dajun
也属于开发者,拥有开发者的所有权限。我们可以定义开发者共有的权限,然后额外为senior
定义一些特殊的权限。
模型文件不用修改,策略文件改动如下:
p, senior, data, write
p, developer, data, read
g, dajun, senior
g, senior, developer
g, lizi, developer
复制代码
上面policy.csv
文件定义了高级开发者senior
对数据data
有write
权限,普通开发者developer
对数据只有read
权限。同时senior
也是developer
,所以senior
也继承其read
权限。dajun
属于senior
,所以dajun
对data
有read
和write
权限,而lizi
只属于developer
,对数据data
只有read
权限。
check(e, "dajun", "data", "read")
check(e, "dajun", "data", "write")
check(e, "lizi", "data", "read")
check(e, "lizi", "data", "write")
复制代码
RBAC
domain
在casbin
中,角色可以是全局的,也可以是特定domain
(领域)或tenant
(租户),可以简单理解为组。例如dajun
在组tenant1
中是管理员,拥有比较高的权限,在tenant2
可能只是个弟弟。
使用RBAC domain
需要对模型文件做以下修改:
[request_definition]
r = sub, dom, obj, act
[policy_definition]
p = sub, dom, obj, act
[role_definition]
g = _,_,_
[matchers]
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.obj
复制代码
g=_,_,_
表示前者在后者中拥有中间定义的角色,在匹配器中使用g
要带上dom
。
p, admin, tenant1, data1, read
p, admin, tenant2, data2, read
g, dajun, admin, tenant1
g, dajun, developer, tenant2
复制代码
在tenant1
中,只有admin
可以读取数据data1
。在tenant2
中,只有admin
可以读取数据data2
。dajun
在tenant1
中是admin
,但是在tenant2
中不是。
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", "tenant1", "data1", "read")
check(e, "dajun", "tenant2", "data2", "read")
}
复制代码
结果不出意料:
dajun CAN read data1 in tenant1
dajun CANNOT read data2 in tenant2
复制代码
ABAC
RBAC
模型对于实现比较规则的、相对静态的权限管理非常有用。但是对于特殊的、动态的需求,RBAC
就显得有点力不从心了。例如,我们在不同的时间段对数据data
实现不同的权限控制。正常工作时间9:00-18:00
所有人都可以读写data
,其他时间只有数据所有者能读写。这种需求我们可以很方便地使用ABAC
(attribute base access list)模型完成:
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[matchers]
m = r.sub.Hour >= 9 && r.sub.Hour < 18 || r.sub.Name == r.obj.Owner
[policy_effect]
e = some(where (p.eft == allow))
复制代码
该规则不需要策略文件:
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)
}
o := Object{"data", "dajun"}
s1 := Subject{"dajun", 10}
check(e, s1, o, "read")
s2 := Subject{"lizi", 10}
check(e, s2, o, "read")
s3 := Subject{"dajun", 20}
check(e, s3, o, "read")
s4 := Subject{"lizi", 20}
check(e, s4, o, "read")
}
复制代码
显然lizi
在20:00
不能read
数据data
:
dajun CAN read data at 10:00
lizi CAN read data at 10:00
dajun CAN read data at 20:00
lizi CANNOT read data at 20:00
复制代码
我们知道,在model.conf
文件中可以通过r.sub
和r.obj
,r.act
来访问传给Enforce
方法的参数。实际上sub/obj
可以是结构体对象,得益于govaluate
库的强大功能,我们可以在model.conf
文件中获取这些结构体的字段值。如上面的r.sub.Name
、r.Obj.Owner
等。govaluate
库的内容可以参见我之前的一篇文章《Go 每日一库之 govaluate》。
使用ABAC
模型可以非常灵活的权限控制,但是一般情况下RBAC
就已经够用了。
模型存储
上面代码中,我们一直将模型存储在文件中。casbin
也可以实现在代码中动态初始化模型,例如get-started
的例子可以改写为:
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, "dajun", "data1", "read")
check(e, "lizi", "data2", "write")
check(e, "dajun", "data1", "write")
check(e, "dajun", "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)
check(e, "dajun", "data1", "read")
check(e, "lizi", "data2", "write")
check(e, "dajun", "data1", "write")
check(e, "dajun", "data2", "read")
}
复制代码
但是这两种方式并不推荐。
策略存储
在前面的例子中,我们都是将策略存储在policy.csv
文件中。一般在实际应用中,很少使用文件存储。casbin
以第三方适配器的方式支持多种存储方式包括MySQL/MongoDB/Redis/Etcd
等,还可以实现自己的存储。完整列表看这里casbin.org/docs/en/ada…。下面我们介绍使用Gorm Adapter
。先连接到数据库,执行下面的SQL
:
CREATE DATABASE IF NOT EXISTS casbin;
USE casbin;
CREATE TABLE IF NOT EXISTS casbin_rule (
p_type VARCHAR(100) NOT NULL,
v0 VARCHAR(100),
v1 VARCHAR(100),
v2 VARCHAR(100),
v3 VARCHAR(100),
v4 VARCHAR(100),
v5 VARCHAR(100)
);
INSERT INTO casbin_rule VALUES
('p', 'dajun', 'data1', 'read', '', '', ''),
('p', 'lizi', 'data2', 'write', '', '', '');
复制代码
然后使用Gorm Adapter
加载policy
,Gorm Adapter
默认使用casbin
库中的casbin_rule
表:
package main
import (
"fmt"
"github.com/casbin/casbin/v2"
gormadapter "github.com/casbin/gorm-adapter/v2"
_ "github.com/go-sql-driver/mysql"
)
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, "dajun", "data1", "read")
check(e, "lizi", "data2", "write")
check(e, "dajun", "data1", "write")
check(e, "dajun", "data2", "read")
}
复制代码
运行:
dajun CAN read data1
lizi CAN write data2
dajun CANNOT write data1
dajun CANNOT read data2
复制代码
使用函数
我们可以在匹配器中使用函数。casbin
内置了一些函数keyMatch/keyMatch2/keyMatch3/keyMatch4
都是匹配 URL 路径的,regexMatch
使用正则匹配,ipMatch
匹配 IP 地址。参见casbin.org/docs/en/fun…。使用内置函数我们能很容易对路由进行权限划分:
[matchers]
m = r.sub == p.sub && keyMatch(r.obj, p.obj) && r.act == p.act
复制代码
p, dajun, user/dajun/*, read
p, lizi, user/lizi/*, read
复制代码
不同用户只能访问其对应路由下的 URL:
func main() {
e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
if err != nil {
log.Fatalf("NewEnforecer failed:%v\n", err)
}
check(e, "dajun", "user/dajun/1", "read")
check(e, "lizi", "user/lizi/2", "read")
check(e, "dajun", "user/lizi/1", "read")
}
复制代码
输出:
dajun CAN read user/dajun/1
lizi CAN read user/lizi/2
dajun CANNOT read user/lizi/1
复制代码
我们当然也可以定义自己的函数。先定义一个函数,返回 bool:
func KeyMatch(key1, key2 string) bool {
i := strings.Index(key2, "*")
if i == -1 {
return key1 == key2
}
if len(key1) > i {
return key1[:i] == key2[:i]
}
return key1 == key2[:i]
}
复制代码
这里实现了一个简单的正则匹配,只处理*
。
然后将这个函数用interface{}
类型包装一层:
func KeyMatchFunc(args ...interface{}) (interface{}, error) {
name1 := args[0].(string)
name2 := args[1].(string)
return (bool)(KeyMatch(name1, name2)), nil
}
复制代码
然后添加到权限认证器中:
e.AddFunction("my_func", KeyMatchFunc)
复制代码
这样我们就可以在匹配器中使用该函数实现正则匹配了:
[matchers]
m = r.sub == p.sub && my_func(r.obj, p.obj) && r.act == p.act
复制代码
接下来我们在策略文件中为dajun
赋予权限:
p, dajun, data/*, read
复制代码
dajun
对匹配模式data/*
的文件都有read
权限。
验证一下:
check(e, "dajun", "data/1", "read")
check(e, "dajun", "data/2", "read")
check(e, "dajun", "data/1", "write")
check(e, "dajun", "mydata", "read")
复制代码
dajun
对data/1
没有write
权限,mydata
不符合data/*
模式,也没有read
权限:
dajun CAN read data/1
dajun CAN read data/2
dajun CANNOT write data/1
dajun CANNOT read mydata
复制代码
总结
casbin
功能强大,简单高效,且多语言通用。值得学习。