Casbin是用于Golang项目的功能强大且高效的开源访问控制库。
强大通用也意味着概念和配置较多,具体到实际应用(以Gin Web框架开发)需要解决以下问题:
- 权限配置的存储,以及
增删改查
- Gin框架的中间件如何实现
经过一番摸索实践出经验,计划分为三个章节,循序渐进的介绍使用方法
1. Casbin概念介绍以及库使用
2. 使用Gorm存储Casbin权限配置以及增删改查
3.实现Gin鉴权中间件
代码地址 https://gitee.com/leobest2/gin-casbin-example
核心配置中含两部分
模型配置
以及策略配置
,给出两个示范配置,在此基础上对实际请求进行分析。
模型文件,存储了请求定义(request_definition),策略定义(policy_definition),匹配规则(matchers),以及匹配的综合结果(policy_effect)
[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
以下为示策略文件
policy.csv
含有两条策略,策略除了存储在文件中,还可以保存到数据库,后续中我们用到GORM Adapter
,保存到数据库中
p,leo,/api/user,GET
p,leo,/api/user,POST
以用户
leo
通过GET
方法访问后台API:/api/user
为例
Casbin模型比较多,只需理解以下两种模型,基本能满足绝大部分业务需求
简单理解,如上面
model.conf
中不包含用户角色组,策略中都是针对单个用户,用户的请求和动作直接匹配策略,并计算结果
简单理解,用户关联到角色组,策略定义中针对组做策略
后续gin casbin鉴权中选用该模型
后续示例中model.conf
[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
定义了两条策略,
admin
组能访问的资源以及操作,以及用户leo
属于admin
组
p,admin,/api/user,GET
p,admin,/api/user,POST
g,leo,admin
Casbin 库中核心概念为
执行器Enforcer
使用casbin.NewEnforcer("./model.conf", "./policy.csv")
加载模型
和策略
调用Enforcer的Enforce(r.sub, r.obj, r.act)
方法检查鉴权结果
package main
import (
"fmt"
"github.com/casbin/casbin/v2"
)
func CheckPermission(e *casbin.Enforcer, sub, obj, act string) {
ok, err := e.Enforce(sub, obj, act)
if err != nil {
panic("check enforce error: " + err.Error())
}
if ok {
fmt.Printf("用户: %s 访问资源: %s 使用方法: %s 检查通过\n", sub, obj, act)
} else {
fmt.Printf("用户: %s 访问资源: %s 使用方法: %s 检查拒绝\n", sub, obj, act)
}
}
func main() {
enforcer, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
if err != nil {
panic("new enforcer error: " + err.Error())
}
// 预期输出:
// 用户: leo 访问资源: /api/user 使用方法: GET 检查通过
CheckPermission(enforcer, "leo", "/api/user", "GET")
// 预期输出:
// 用户: leo 访问资源: /api/user 使用方法: DELETE 检查拒绝
CheckPermission(enforcer, "leo", "/api/user", "DELETE")
}
casbin.NewEnforcer(“./model.conf”, “./policy.csv”)中默认从文件加载,是内置的名为
File Adapter (内置)
实现的
后续中,我们需将权限存储到DB中,使用的适配器为GORM Adapter
,使用如下:
package main
import (
"log"
"github.com/casbin/casbin/v2"
gormadapter "github.com/casbin/gorm-adapter/v3"
"github.com/glebarez/sqlite"
"gorm.io/gorm"
)
func main() {
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
a, err := gormadapter.NewAdapterByDB(db)
if err != nil {
panic("new gorm adapter error: " + err.Error())
}
e, err := casbin.NewEnforcer("./model.conf", a)
if err != nil {
panic("new casbin enforcer error: " + err.Error())
}
e.LoadPolicy()
// 添加策略
ok, err := e.AddPolicy("admin", "/api/user", "GET")
log.Println("add admin /api/user GET: ", ok, err)
ok, err = e.AddGroupingPolicy("leo", "admin")
log.Println("add leo to admin group: ", ok, err)
e.SavePolicy()
ok, err = e.Enforce("leo", "/api/user", "GET")
log.Println("leo GET /api/user :", ok, err)
ok, err = e.Enforce("leo", "/api/user", "DELETE")
log.Println("leo DELETE /api/user :", ok, err)
}
测试结果
上述
model.conf
中有一个问题,访问的url是/api/user/123
形式,r.obj
与p.obj
不匹配,这时候我们要用到Matchers中的函数,一般选择keyMatch2
即可能针对url,能满足日常需求
修改后的model.conf
[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) && keyMatch2(r.obj,p.obj) && r.act == p.act
函数 | url | 模式 |
---|---|---|
keyMatch | 一个URL 路径,例如/alice_data/resource1 | 一个URL 路径或* 模式下,例如/alice_data/* |
keyMatch2 | 一个URL 路径,例如/alice_data/resource1 | 一个URL 路径或: 模式下,例如/alice_data/:resource |
keyMatch3 | 一个URL 路径,例如/alice_data/resource1 | 一个URL 路径或{} 模式下,例如/alice_data/{resource} |
keyMatch4 | 一个URL 路径,例如/alice_data/resource1 | 一个URL 路径或{} 模式下,例如/alice_data//{id}/book/{id} |
keyMatch5 | a URL path like/alice_data/123/?status=1 | a URL path, a{} or* pattern like/alice_data/{id}/* |
regexMatch | 任意字符串 | 正则表达式模式 |
至此,已了解的概念已能满足业务需求,下一章将
Casbin
与Gorm
结合起来,并实现增删改查
功能