casbin学习笔记

本文介绍了casbin权限管理系统的基础知识,包括安装、工作原理、模型(ACL、RBAC、ABAC)详解,以及如何在实际项目中应用和存储策略。涵盖了自定义函数、多层角色、RBAC domain等内容,适合开发者理解和实践权限控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


与你相识


博主介绍:

– 本人是普通大学生一枚,每天钻研计算机技能,CSDN主要分享一些技术内容,因我常常去寻找资料,不经常能找到合适的,精品的,全面的内容,导致我花费了大量的时间,所以会将摸索的内容全面细致记录下来。另外,我更多关于管理,生活的思考会在简书中发布,如果你想了解我对生活有哪些反思,探索,以及对管理或为人处世经验的总结,我也欢迎你来找我。

– 目前的学习专注于Go语言,辅学算法,前端领域。也会分享一些校内课程的学习,例如数据结构,计算机组成原理等等,如果你喜欢我的风格,请关注我,我们一起成长。



casbin

权限管理几乎在每个系统中都是必备的模块。如果项目开发每次都要实现一次权限管理,会浪费很多的时间,而casbin就来做这个事情,支持常用的多种访问控制模型,如ACL/RBAC/ABAC等。可以实现灵活的访问权限控制。

比如说什么角色,什么用户,可以通过某个api,就可以使用casbin来进行限制。

官方文档

由于官方文档到中间靠后的部分有点难以理解,所以就转向其它教程了。

基础知识

安装及简单实用
go get github.com/casbin/casbin

另外创建一个Casbin决策器需要有一个模型文件和策略文件作为参数:

import "github.com/casbin/casbin"

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

然后可以在访问发生之前,给代码添加强制挂钩:

sub := "alice" // 想要访问资源的用户。
obj := "data1" //要访问的资源。
act := "read" // 用户对资源执行的操作。

if e.Enforce(sub, obj, act) == true {
    // 允许alice读取data1
} else {
    // 拒绝请求,显示错误
}
工作原理

casbin的访问控制模型被抽象为基于PERM(Policy(策略), Effect(效果), Request(请求), Matcher(匹配器))的一个文件。

Casbin中最基本,最简单的model是ACLACL中的model CONF为:

  # 请求定义
    [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 = r.sub == p.sub && r.obj == p.obj \ 
  && r.act == p.act

policy如下:

// 这表示alice可以读取data1
    p, alice, data1, read
// 这表示bob可以编写data2
    p, bob, data2, write

Model

支持的Model
  1. ACL (Access Control List, 访问控制列表)
  2. 具有超级用户的 ACL
  3. 没有用户的 ACL: 对于没有身份验证或用户登录的系统尤其有用。
  4. 没有资源的 ACL: 某些场景可能只针对资源的类型, 而不是单个资源, 诸如write-article,read-log等权限。 它不控制对特定文章或日志的访问。
  5. RBAC (基于角色的访问控制)
  6. 支持资源角色的RBAC: 用户和资源可以同时具有角色 (或组)。
  7. 支持域/租户的RBAC: 用户可以为不同的域/租户设置不同的角色集。
  8. ABAC (基于属性的访问控制): 支持利用resource.Owner这种语法糖获取元素的属性。
  9. RESTful: 支持路径, 如/res/*,/res/: id和 HTTP 方法, 如GET,POST,PUT,DELETE
  10. 拒绝优先: 支持允许和拒绝授权, 拒绝优先于允许。
  11. 优先级: 策略规则按照先后次序确定优先级,类似于防火墙规则。
Model语法
  • Model CONF 至少应包含四个部分:[request_definition], [policy_definition], [policy_effect], [matchers]
  • 如果 model 使用 RBAC, 还需要添加[role_definition]部分。
Request定义

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

[request_definition]
r = sub, obj, act

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

Policy定义

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

[policy_definition]
p = sub, obj, act

这些是我们对policy规则的具体描述

p, alice, data1, read

policy部分的每一行称之为一个策略规则。 上面的policy的绑定关系将会在matcher中使用, 罗列如下:

(alice, data1, read) -> (p.sub, p.obj, p.act)
Policy effect定义

[policy_effect]部分是对policy生效范围的定义, 原语定义了当多个policy rule同时匹配访问请求request时,该如何对多个决策结果进行集成以实现统一决策。 以下示例展示了一个只有一条规则生效,其余都被拒绝的情况:

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

该Effect原语表示如果存在任意一个决策结果为allow的匹配规则,则最终决策结果为allow。 其中p.eft表示策略规则的决策结果,可以为allow或者deny,当不指定规则的决策结果时,取默认值allow。 通常情况下,policy的p.eft默认为allow, 因此前面例子中都使用了这个默认值。

这是另一个policy effect的例子:

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

该Effect原语表示不存在任何决策结果为deny的匹配规则,则最终决策结果为allow,即deny-override。some量词判断是否存在一条策略规则满足匹配器。另外any量词则判断是否所有的策略规则都满足匹配器。 policy effect还可以利用逻辑运算符进行连接:

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

该Effect原语表示当至少存在一个决策结果为allow的匹配规则,且不存在决策结果为deny的匹配规则时,则最终决策结果为allow。 这时allow授权和deny授权同时存在,但是deny优先。

Matchers

[matchers]原语定义了策略规则如何与访问请求进行匹配的匹配器,其本质上是布尔表达式,可以理解为Request、Policy等原语定义了关于策略和请求的变量,然后将这些变量代入Matcher原语中求值,从而进行策略决策。

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

这是一个简单的例子,该Matcher原语表示,访问请求request中的subject、object、action三元组应与策略规则policy rule中的subject、object、action三元组分别对应相同。

Matcher原语支持+、 -、 *、 /等算数运算符,==,、!=、 >、 <等关系运算符以及&& (与)、|| (或)、 ! (非)等逻辑运算符。

内置函数
函数释义示例
keyMatch(arg1, arg2)参数 arg1 是一个 URL 路径,例如/alice_data/resource1,参数 arg2 可以是URL路径或者是一个*模式,例如/alice_data/*。此函数返回 arg1是否与 arg2 匹配。keymatch_model.conf/keymatch_policy.csv
keyMatch2(arg1, arg2)参数 arg1 是一个 URL 路径,例如/alice_data/resource1,参数 arg2 可以是 URL 路径或者是一个:模式,例如/alice_data/:resource。此函数返回 arg1 是否与 arg2 匹配。keymatch2_model.conf/keymatch2_policy.csv
regexMatch(arg1, arg2)arg1 可以是任何字符串。arg2 是一个正则表达式。它返回 arg1 是否匹配 arg2。keymatch_model.conf/keymatch_policy.csv
ipMatch(arg1, arg2)arg1 是一个 IP 地址, 如192.168.2.123。arg2 可以是 IP 地址或 CIDR, 如192.168.2. 0/24。它返回 arg1 是否匹配 arg2。ipmatch_model.conf/ipmatch_policy.csv

也可以添加自定义函数,具体参考:添加自定义函数

RBAC

看不懂

ABAC

看不懂

每日一库——casbin

ACL模型

下面可以看到我们使用ACL模型进行的权限控制

我们依然使用 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对数据data1read权限,lizi对数据data2write权限。

接下来就是使用的代码:

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"没有对data1write权限,第 4 个因为dajundata2没有read权限,所以检查都不能通过。输出结果符合预期。

sub/obj/act依次对应传给Enforce方法的三个参数。实际上这里的sub/obj/actread/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在用户和资源比较少的情况下没有什么问题,但是如果用户很多的话,就会显得非常的繁琐,试想一下每次新增一个用户,都要把他需要的权限重新设置一遍是多么地痛苦。

所以RBAC就通过引入角色(role)来解决这个问题,每个用户都属于一个角色,每个角色都有其特定的权限,这样新增用户的时候,只需要给他指派一个角色,他就可以拥有该角色对应的权限信息。

使用RBAC模型需要在ACLMODEL的基础上添加role_definition模块:

g = _,_定义了用户——角色,角色——角色的映射关系,前者是后者的成员,拥有后者的权限。然后在匹配器中,我们不需要判断r.subp.sub是否相当,只需要使用g(r.sub, p.sub)来判断请求主体r.sub是否属于p.sub这个角色即可。

[role_definition]
g = _, _

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

最后再修改策略文件,下面的文件就规定了dajun属于admin管理员,lizi属于developer开发者,使用g来定义这层关系。

另外具体的角色,如admin对数据data有rede和write权限也通过p来定义。

p, admin, data, read
p, admin, data, write
p, developer, data, read
g, dajun, admin
g, lizi, developer

我们编写主程序

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")
}

结果:

dajun CAN read data
dajun CAN write data
lizi CAN read data
lizi CANNOT write data
多个RBAC

可以为用户和资源都赋予角色的概念

[role_definition]
g=_,_
g2=_,_

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

上面的模型文件定义了两个RBAC系统gg2,我们在匹配器中使用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角色拥有对proddev类资源的读写权限,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")
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
多层角色

可以为角色定义所属角色,这种权限关系可以进行传递。

例如dajun属于高级开发者seniorseinor属于开发者,那么dajun也是开发者,拥有开发者的所有权限,那么我们就可以定义开发者共有的权限,然后额外为高级开发者senior定义一些特殊的权限。

模型文件不需要修改,策略文件改动如下:

# 定义了senior对数据data有write权限
p, senior, data, write
# 定义了developer对数据data有read权限
p, developer, data, read
# 为dajun赋予senior权限
g, dajun, senior
# 为senior赋予developer权限,senior权限本身对data有write权限,又被加了一个developer权限,就可写可读了。
g, senior, developer
# 为lizi赋予developer权限
g, lizi, developer
RBAC domain

角色可以是全局的,也可以是特定域(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

# admin在tenant1中对data1有read权限
p, admin, tenant1, data1, read
# admin在tenant2中对data2有read权限
p, admin, tenant2, data2, read
# dajun在tenant1中的角色是admin
g, dajun, admin, tenant1
# dajun在tenant2中的角色是developer
g, dajun, developer, 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模型对于实现比较规则的、相对静态的权限管理比较好用,但是例如我们需要在不同的时间段对数据data实现不同的权限控制,比如正常的工作时间9:00-18:00所有人都可以读写data,其它时间只有数据所有者能读写。这种需求就需要使用ABAC模型完成。

首先修改model文件:

[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))

ABAC模型不需要策略文件:

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")
}
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

使用ABAC模型可以非常灵活的进行权限控制,但是在一般情况的RBAC就够用了。

模型存储

casbin可以实现在代码中动态初始化模型:

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")
}

但是这两种方式都不推荐使用

策略存储

在前面的例子中,我们都是将策略存储在一个.csv文件中,但是实际应用中一般不用这种方式存储,casbin以第三方适配器的方式支持多种存储方式,包括Mysql/MongoDB/Redis/Etcd等。

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加载policyGorm 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 地址。参见https://casbin.org/docs/en/function。使用内置函数我们能很容易对路由进行权限划分:

[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")

dajundata/1没有write权限,mydata不符合data/*模式,也没有read权限:

dajun CAN read data/1
dajun CAN read data/2
dajun CANNOT write data/1
dajun CANNOT read mydata

参考资料


欢迎评论区讨论,或指出问题。 如果觉得写的不错,欢迎点赞,转发,收藏。

### Java中使用Casbin的概述 Casbin是一个强大的开源访问控制库,不仅适用于Golang,在Java环境中同样可以应用来实现细粒度的访问控制[^3]。该框架支持多种访问控制模型,如ACL(访问控制列表)、RBAC(基于角色的访问控制)以及ABAC(基于属性的访问控制),旨在为开发人员提供灵活性和易用性的解决方案。 ### 配置环境并引入依赖项 为了在Java项目里集成Casbin,首先需要配置Maven或Gradle构建工具中的依赖关系。对于Maven而言,可以在`pom.xml`文件内加入如下片段: ```xml <dependency> <groupId>org.casbin</groupId> <artifactId>casbin-spring-boot-starter</artifactId> <version>LATEST_VERSION_HERE</version> </dependency> ``` 请注意替换`LATEST_VERSION_HERE`为你所期望安装的具体版本号。 ### 创建自定义权限验证逻辑 下面展示了一个简单的例子,说明如何利用Casbin来进行基本的身份认证与授权操作: #### 定义Model.conf 文件 创建名为 `model.conf` 的配置文件用于描述访问控制系统的行为模式, 如下所示: ```plaintext [request_definition] r = sub, obj, act [policy_definition] p = sub, obj, act [role_definition] g = _, _ [policy_effect] e = some(where (p.eft == allow)) [matchers] m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act ``` 此配置表示采用最基础的角色继承加对象-动作匹配的方式进行权限判断。 #### 编写Policy.csv 文件 接着准备一份CSV格式的数据表作为初始策略集的一部分,命名为policy.csv : ```csv p, alice, data1, read p, bob, data2, write g, alice, admin ``` 上述内容意味着赋予用户alice读取data1资源的权利;而bob则被允许修改data2资料;另外还指定了alice属于admin组成员身份。 #### 初始化Enforcer实例 最后一步是在应用程序启动阶段加载这些设定,并初始化一个enforcer对象供后续调用: ```java import org.casbin.jcasbin.main.Enforcer; public class CasbinInitializer { private static final String MODEL_PATH = "path/to/model.conf"; private static final String POLICY_PATH = "path/to/policy.csv"; public static void init() throws Exception{ Enforcer enforcer = new Enforcer(MODEL_PATH,POLICY_PATH); // 测试是否能正常工作 boolean result = enforcer.enforce("alice", "data1", "read"); System.out.println(result); // 应输出true // 将enforcer注册到Spring上下文中以便其他组件注入使用... } } ``` 通过以上步骤即可完成一次完整的Java环境下Casbin接入流程演示。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jacob_云飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值