• Go Gin Gorm Casbin权限管理实现 - 1. Casbin概念介绍以及库使用


    0. 背景

    Casbin是用于Golang项目的功能强大且高效的开源访问控制库。
    强大通用也意味着概念和配置较多,具体到实际应用(以Gin Web框架开发)需要解决以下问题:

    • 权限配置的存储,以及增删改查
    • Gin框架的中间件如何实现

    经过一番摸索实践出经验,计划分为三个章节,循序渐进的介绍使用方法
    1. Casbin概念介绍以及库使用
    2. 使用Gorm存储Casbin权限配置以及增删改查
    3.实现Gin鉴权中间件

    代码地址 https://gitee.com/leobest2/gin-casbin-example

    1. 核心概念

    核心配置中含两部分模型配置以及策略配置,给出两个示范配置,在此基础上对实际请求进行分析。

    1.1 Model

    模型文件,存储了请求定义(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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    1.2 Policy

    以下为示策略文件policy.csv含有两条策略,策略除了存储在文件中,还可以保存到数据库,后续中我们用到GORM Adapter,保存到数据库中

    p,leo,/api/user,GET
    p,leo,/api/user,POST
    
    • 1
    • 2

    1.3 实例分析

    以用户leo通过GET方法访问后台API:/api/user为例

    根据request_definition对应request中三个参数为
    matchers根据条件匹配策略,不匹配的忽略
    matchers根据条件匹配策略,不匹配的忽略
    matchers根据条件匹配策略,不匹配的忽略
    policy_effect计算影响,some(where (p.eft == allow))表示其中一条匹配即通过
    用户`leo`通过`GET`方法访问`/api/user`
    (leo, /api/user, GET)->(r.sub, r.obj, r.act)
    匹配策略1
    匹配策略2
    匹配策略....
    返回最终结果通过或者拒绝

    1.3 ACL模型和RBAC模型

    Casbin模型比较多,只需理解以下两种模型,基本能满足绝大部分业务需求

    1.3.1 ACL模型

    简单理解,如上面model.conf中不包含用户角色组,策略中都是针对单个用户,用户的请求和动作直接匹配策略,并计算结果

    1.3.2 RBAC模型

    简单理解,用户关联到角色组,策略定义中针对组做策略

    后续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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    后续示例中policy.csv

    定义了两条策略,admin组能访问的资源以及操作,以及用户leo属于admin

    p,admin,/api/user,GET
    p,admin,/api/user,POST
    
    g,leo,admin
    
    • 1
    • 2
    • 3
    • 4

    2. 库使用

    2.1 Enforcer 执行器概念

    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")
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    2.2 adapter 适配器概念

    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)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    测试结果

    2.3 Functions(Matchers中的函数)

    上述model.conf中有一个问题,访问的url是/api/user/123形式,r.objp.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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    更多函数参考,https://casbin.org/zh/docs/function

    函数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}
    keyMatch5a URL path like/alice_data/123/?status=1a URL path, a{}or*pattern like/alice_data/{id}/*
    regexMatch任意字符串正则表达式模式

    3. 结语

    至此,已了解的概念已能满足业务需求,下一章将CasbinGorm结合起来,并实现增删改查功能

  • 相关阅读:
    基于openeuler的NAT服务器查看流向内部服务端口的流量
    十分钟入门以太和Opensea测试网批量发行NFT实战
    单链表操作 C实现
    怎么快速入门一种编程语言
    SSL证书对网站SEO的好处
    C# | AES加解密 - 快速上手
    物流信息混合查询,多家快递同时查询省时又省力
    opensmile学习使用
    keepalived识别MGR主节点
    智能插帧,打造丝滑视频体验
  • 原文地址:https://blog.csdn.net/LeoForBest/article/details/133607878