Go中最强大的权限控制库(Casbin)的实现

 更新时间:2026年03月31日 08:52:36   作者:我叫黑大帅  
Casbin是一个强大的、高效的开源访问控制框架,支持ACL、RBAC、ABAC 等多种经典访问控制模型,通过配置文件即可灵活定义权限规则,具有一定的参考价值,感兴趣的可以了解一下

权限控制,它决定了 “谁能访问什么资源,能做什么操作”。

Casbin 是一个强大的、高效的开源访问控制框架,支持 ACL、RBAC、ABAC 等多种经典访问控制模型,通过配置文件即可灵活定义权限规则,同时支持策略的动态管理和持久化存储。

概念作用说明
Model(模型)定义权限控制的逻辑用 CONF 格式的文件或字符串编写,定义 “请求是什么、策略是什么、如何匹配、结果是什么”
Policy(策略)定义具体的权限规则可以存储在文件、数据库中,定义 “谁(用户 / 角色)能对什么资源做什么操作”
Adapter(适配器)负责策略的存储和加载支持文件、MySQL、PostgreSQL、Redis、MongoDB 等多种存储方式
Enforcer(执行器)Casbin 的核心组件加载 Model 和 Policy,提供权限判断、策略管理等核心 API

ACL(访问控制列表)

ACL 是最简单的访问控制模型,直接定义 “用户 → 资源 → 操作” 的权限关系,适合小型项目或简单的权限场景。

编写 Model 文件(model.conf

Model 文件定义了权限控制的逻辑,Casbin 通过它来理解如何判断权限。

[request_definition]
# 定义请求的格式:r = [主体(sub), 客体(obj), 动作(act)]
# sub:用户/角色;obj:资源;act:操作(如 read、write)
r = sub, obj, act
[policy_definition]
# 定义策略的格式:p = [主体(sub), 客体(obj), 动作(act)]
p = sub, obj, act
[policy_effect]
# 定义策略效果:e = some(where (p.eft == allow))
# 意思是:只要有一条策略匹配且效果为 allow,就允许访问
e = some(where (p.eft == allow))
[matchers]
# 定义匹配规则:m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
# 意思是:请求的 sub、obj、act 必须和策略完全一致才匹配
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act

编写 Policy 文件(policy.csv

Policy 文件定义了具体的权限规则,用 CSV 格式存储。

# p, 主体, 客体, 动作
p, zhangsan, /api/user, read
p, zhangsan, /api/user, write
p, lisi, /api/article, read

上面的策略表示:

  • zhangsan 可以对 /api/user 资源进行 read 和 write 操作
  • lisi 可以对 /api/article 资源进行 read 操作

初始化 Enforcer:加载 Model 文件和 Policy 文件

// 参数 1:Model 文件路径
// 参数 2:Policy 文件路径
e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
if err != nil {
        fmt.Printf("初始化 Enforcer 失败:%v\n", err)
        return
}
  • casbin.NewEnforcer(modelPath, policyPath) :初始化 Enforcer,加载 Model 和 Policy。

权限判断:使用 Enforce 方法

// 参数顺序:sub, obj, act(和 Model 中 r 的定义一致)
// 场景 1:zhangsan 读取 /api/user
ok, err := e.Enforce("zhangsan", "/api/user", "read")
if err != nil {
        fmt.Printf("权限判断失败:%v\n", err)
        return
}
if ok {
        fmt.Println("zhangsan 允许读取 /api/user")
} else {
        fmt.Println("zhangsan 不允许读取 /api/user")
}
// 场景 2:lisi 写入 /api/article(策略中没有这条,应该拒绝)
ok, _ = e.Enforce("lisi", "/api/article", "write")
if ok {
        fmt.Println("lisi 允许写入 /api/article")
} else {
        fmt.Println("lisi 不允许写入 /api/article")
}
  • e.Enforce(sub, obj, act) :核心权限判断方法,参数顺序必须和 Model 中 r 的定义一致,返回 bool 表示是否允许访问。

RBAC(基于角色的访问控制)

RBAC 是企业开发中最常用的权限模型,它通过 “角色” 作为中间层,将用户与权限解耦(用户 → 角色 → 权限),大大简化了权限管理(比如给用户分配角色即可获得该角色的所有权限,无需逐个分配)。

编写 RBAC Model 文件(rbac_model.conf)

RBAC 模型在 ACL 的基础上增加了角色定义(g) 和 角色继承。

[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
# 定义角色关系:g = [用户, 角色]
# 表示“用户属于某个角色”
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
# 匹配规则:g(r.sub, p.sub) 表示“请求的用户属于策略中的角色”
# 或者请求的用户直接等于策略中的主体(支持用户直接分配权限)
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act

编写 RBAC Policy 文件(rbac_policy.csv)

  • 角色权限:

    • admin 可以对 /api/user 和 /api/article 进行 read 和 write
    • editor 可以对 /api/article 进行 read 和 write
    • viewer 只能对 /api/article 进行 read
  • 用户角色:

    • zhangsan 是 admin
    • lisi 是 editor
    • wangwu 是 viewer
# 1. 角色权限策略:p, 角色, 资源, 动作
p, admin, /api/user, read
p, admin, /api/user, write
p, admin, /api/article, read
p, admin, /api/article, write
p, editor, /api/article, read
p, editor, /api/article, write
p, viewer, /api/article, read
# 2. 用户角色策略:g, 用户, 角色
g, zhangsan, admin
g, lisi, editor
g, wangwu, viewer

动态管理用户角色

// 给 wangwu 添加 editor 角色(现在 wangwu 是 viewer + editor)
added, err := e.AddRoleForUser("wangwu", "editor")
if added {
        // 保存策略到文件(生产环境用数据库适配器自动保存)
        e.SavePolicy()
}
// 现在 wangwu 应该允许写入 /api/article 了
ok, _ = e.Enforce("wangwu", "/api/article", "write")
// 删除 wangwu 的 viewer 角色
removed, err := e.DeleteRoleForUser("wangwu", "viewer")
if removed {
        e.SavePolicy()
}

动态管理权限

// 给 editor 角色添加 /api/user 的 read 权限
added, err = e.AddPolicy("editor", "/api/user", "read")
if added {
        e.SavePolicy()
}
// 现在 lisi(editor)应该允许读取 /api/user 了
ok, _ = e.Enforce("lisi", "/api/user", "read")
API作用
e.AddRoleForUser(user, role)给用户添加角色
e.DeleteRoleForUser(user, role)删除用户的角色
e.GetRolesForUser(user)获取用户的所有角色
e.GetUsersForRole(role)获取拥有该角色的所有用户
e.AddPolicy(sub, obj, act)添加权限策略
e.DeletePolicy(sub, obj, act)删除权限策略
e.SavePolicy()保存策略到存储(文件 / 数据库)

RBAC with Domains(多租户 / 多部门)

如果你的系统是多租户(如 SaaS 平台)或多部门的,需要隔离不同租户 / 部门的权限,Casbin 支持 RBAC with Domains 模型,轻松实现权限隔离。

在 request_definition 和 matchers 中增加 dom(域 / 租户)字段:

[request_definition]
r = sub, dom, obj, act
[policy_definition]
p = sub, dom, obj, act
[role_definition]
g = _, _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, r.dom, p.sub, p.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act

权限判断和角色管理时需要增加 dom 参数:

// 权限判断:sub, dom, obj, act
e.Enforce("zhangsan", "tenant1", "/api/user", "read")
// 给用户添加租户下的角色
e.AddRoleForUserInDomain("zhangsan", "admin", "tenant1")

数据库适配器

在开发环境中,我们可以用文件存储 Policy,但在生产环境中,通常需要用数据库存储 Policy,方便动态管理和持久化。Casbin 提供了丰富的数据库适配器,这里以最常用的 GORM Adapter(配合 MySQL)为例。

// 1. 连接 MySQL 数据库
dsn := "root:your_password@tcp(127.0.0.1:3306)/casbin_demo?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
// 2. 初始化 GORM Adapter
// 参数 1:GORM DB 实例
// 参数 2:是否自动迁移(创建 casbin_rule 表)
a, err := gormadapter.NewAdapterByDB(db)
// 3. 初始化 Enforcer:加载 Model 文件和数据库 Adapter
e, err := casbin.NewEnforcer("./rbac_model.conf", a)
// 4. 初始化策略(仅第一次运行时执行,后续可注释)
// 添加角色权限
e.AddPolicy("admin", "/api/user", "read")
e.AddPolicy("admin", "/api/user", "write")
// 添加用户角色
e.AddRoleForUser("zhangsan", "admin")
// 保存策略到数据库
e.SavePolicy()
// 5. 权限判断
ok, _ := e.Enforce("zhangsan", "/api/user", "write")
// 6. 动态修改策略(自动同步到数据库)
e.AddRoleForUser("wangwu", "editor")
ok, _ = e.Enforce("wangwu", "/api/article", "write")
  • 自动同步:使用数据库 Adapter 后,调用 AddPolicyAddRoleForUser 等 API 时,策略会自动同步到数据库,无需手动调用 SavePolicy()(部分 Adapter 需要,GORM Adapter 自动同步)。
  • 持久化:策略存储在数据库中,服务重启后不会丢失。
  • 动态管理:可以通过数据库直接管理策略,或通过后台管理界面调用 Casbin API 管理。

最佳实践

Model 设计

  • Model 文件独立存储:将 Model 文件放在项目的 config 目录下,不要硬编码在代码里。
  • 从简单到复杂:优先使用 RBAC,只有在需要属性级权限控制时才用 ABAC。
  • 合理使用通配符:Casbin 支持 * 通配符(如 p, admin, *, * 表示 admin 可以访问所有资源的所有操作),但要谨慎使用,避免权限过大。

策略管理

  • 生产环境用数据库 Adapter:不要用文件存储 Policy,推荐用 GORM Adapter 或 Redis Adapter。
  • 策略缓存:Casbin 内置了策略缓存,高并发场景下可大幅提升性能,默认开启。
  • 定期备份策略:定期备份数据库中的策略表,防止误操作导致策略丢失。

性能优化

  • 使用 EnforceContext:高并发场景下使用 EnforceContext 替代 Enforce,支持上下文传递和超时控制。
  • 批量权限判断:使用 BatchEnforce 进行批量权限判断,性能更高。
  • 合理设计索引:如果使用数据库 Adapter,确保 casbin_rule 表有合理的索引(GORM Adapter 会自动创建)。

安全注意事项

  • 不要在策略中存储敏感信息:策略仅存储权限规则,不要存储密码、密钥等敏感信息。
  • 最小权限原则:给用户和角色分配最小必要的权限,避免权限过大。
  • 权限验证前置:在 Gin/Echo 等框架的中间件中统一进行权限验证,避免每个接口都写权限判断代码。

到此这篇关于Go中最强大的权限控制库(Casbin)的实现的文章就介绍到这了,更多相关Go Casbin权限控制库内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Golang Defer基础操作详解

    Golang Defer基础操作详解

    在golang当中,defer代码块会在函数调用链表中增加一个函数调用。这个函数调用不是普通的函数调用,而是会在函数正常返回,也就是return之后添加一个函数调用。因此,defer通常用来释放函数内部变量
    2022-10-10
  • Golang优雅关闭channel的方法示例

    Golang优雅关闭channel的方法示例

    Goroutine和channel是Go在“并发”方面两个核心feature,下面这篇文章主要给大家介绍了关于Golang如何优雅关闭channel的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考解决,下面来一起看看吧。
    2017-11-11
  • Go标准库之Requests的介绍与基本使用

    Go标准库之Requests的介绍与基本使用

    Python中的Requests库非常强大,所以Go开发者模仿Python的Requests库,由此诞生了Grequests库,本文主要介绍了Requests的基本使用,有需要的可以参考下
    2024-04-04
  • Go使用协程交替打印字符

    Go使用协程交替打印字符

    这篇文章主要介绍了Go使用协程交替打印字符,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • Go channel实现原理分析

    Go channel实现原理分析

    Channel是go语言内置的一个非常重要的特性,也是go并发编程的两大基石之一,下面这篇文章主要给大家介绍了关于Go中channel的相关资料,需要的朋友可以参考下
    2023-04-04
  • golang根据生日计算星座和属相实例

    golang根据生日计算星座和属相实例

    这篇文章主要为大家介绍了golang根据生日计算星座和属相的示例代码,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • Go语言学习函数+结构体+方法+接口

    Go语言学习函数+结构体+方法+接口

    这篇文章主要介绍了Go语言学习函数+结构体+方法+接口,文章围绕主题的相关资料展开详细的文章说明,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-05-05
  • Go语言中html/template模块详细功能介绍与示例代码

    Go语言中html/template模块详细功能介绍与示例代码

    这篇文章主要介绍了Go语言中html/template模块详细功能介绍与示例代码,这里说的是go 语言中自带的包html/template里的一些基本操作,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-03-03
  • 一文带你深入了解Go语言中的事务

    一文带你深入了解Go语言中的事务

    事务中止时,你结束事务了吗?在开发时有可能就会犯这样的错误,其问题就是你在提交事务时,如果中间有其他业务就取消操作,那么事务也关闭了吗?本文就来详细讲讲
    2023-04-04
  • Go读写锁操作方法示例详解

    Go读写锁操作方法示例详解

    这篇文章主要为大家介绍了Go读写锁方法示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07

最新评论