这里或许是互联网从业者的最后一片净土,随客社区期待您的加入!
您需要 登录 才可以下载或查看,没有账号?立即注册
×
在开发后台权限系统时,我们常常需要一套灵活、可扩展、易维护的权限管理机制,特别是在支持多租户、多平台、多角色的企业系统中。经过一番调研,我最终选择了 Go + Gin + Casbin 的组合,实现基于角色的访问控制(RBAC)。
本文将完整介绍这套方案的设计思路、实战代码以及一些细节优化,适合有权限控制需求的开发者参考使用。
一、项目需求要构建一个健壮的权限系统,需要解决以下几个问题: - 支持角色的继承(如:admin 继承 user)
- 支持 RESTful API 的路径匹配(如 /users/:id)
- 支持 HTTP 方法级别控制(GET/POST/PUT/DELETE)
- 支持平台模式(单租户 / 多租户 / 混合模式)
- 公共接口不需要登录也可访问
二、Casbin 权限模型设计
Casbin 通过配置 .conf 模型文件来定义访问控制逻辑。以下是我设计的一份多平台、角色继承、REST 路径匹配的模型: - [request_definition]
- r = mod, sub, obj, act
- [policy_definition]
- p = mod, sub, obj, act, eft
- [role_definition]
- g = *, *
- [policy_effect]
- e = some(where (p.eft == allow))
- [matchers]
- m = r.sub == "root" ||
- (g(r.sub, p.sub) &&
- g(r.mod, p.mod) &&
- (r.obj == p.obj || keyMatch2(r.obj, p.obj) || keyMatch(r.obj, p.obj) || p.obj == "*") &&
- (r.act == p.act || p.act == "*"))
复制代码 模型说明:
mod 表示平台模式(multi/single tenant) sub 表示用户角色(如 admin/user) obj 是请求路径,支持通配符或 keyMatch2 动态匹配 act 是 HTTP 方法(GET/POST 等) root 用户直接绕过权限判断,拥有所有权限
三、策略规则配置(policy.csv)策略规则可采用 CSV 文件或数据库存储。以下是一个示例策略: - # 角色继承
- g, admin, network_admin
- g, network_admin, user
- g, user, *
- # 平台模式继承
- g, MultiTenantCrossPlatform, MultiTenantSinglePlatform
- g, MultiTenantSinglePlatform, SingleTenantCrossPlatform
- g, SingleTenantCrossPlatform, SingleTenantSinglePlatform
- # 公共路由
- p, SingleTenantSinglePlatform, *, /healths, GET, allow
- p, SingleTenantSinglePlatform, *, /login, POST, allow
- # 用户路由
- p, MultiTenantSinglePlatform, root, /organizations/:organizationId/users, GET, allow
- p, SingleTenantSinglePlatform, admin, /users, GET, allow
- p, SingleTenantSinglePlatform, user, /user, GET, allow
复制代码 四、Go 项目中集成 Casbin1. 使用 embed 内嵌配置文件将模型与策略文件打包进二进制中,避免部署时漏传文件: - package routers
- import "embed"
- //go:embed model.conf policy.csv
- var fs embed.FS
- func MustAssetString(name string) string {
- data, err := fs.ReadFile(name)
- if err != nil {
- panic(err)
- }
- return string(data)
- }
复制代码 2. 初始化 Casbin Enforcer- type Auth struct {
- Enforcer *casbin.Enforcer
- }
- func NewAuth() *Auth {
- m := model.NewModel()
- if err := m.LoadModelFromText(routers.MustAssetString("model.conf")); err != nil {
- logrus.Panicf("load casbin model failed: %v", err)
- }
- e, err := casbin.NewEnforcer(m, textadapter.NewAdapter(routers.MustAssetString("policy.csv")))
- if err != nil {
- logrus.Panicf("new enforcer failed: %v", err)
- }
- return &Auth{Enforcer: e}
- }
复制代码 3. Gin 中间件实现权限控制- func (a *Auth) HandlerFunc() gin.HandlerFunc {
- return func(c *gin.Context) {
- user, valid, err := a.validateByAuthorization(c)
- if err != nil {
- c.JSON(401, gin.H{"error": "Unauthorized"})
- c.Abort()
- return
- }
- if !valid {
- user, valid, err = a.validateByCookie(c)
- if err != nil {
- c.JSON(401, gin.H{"error": "Unauthorized"})
- c.Abort()
- return
- }
- }
- var ok bool
- if valid {
- ok, _ = a.checkPermission(user, c.Request.URL.Path, c.Request.Method)
- } else {
- ok, _ = a.checkPublicAccess(c.Request.URL.Path, c.Request.Method)
- }
- if ok {
- c.Next()
- return
- }
- c.JSON(401, gin.H{"error": "Permission denied"})
- c.Abort()
- }
- }
- func (a *Auth) checkPermission(user *models.User, path, method string) (bool, error) {
- return a.Enforcer.Enforce(
- systems.GetPlatformMode(), // 平台模式
- fmt.Sprintf("%v", user.Role),
- path,
- method,
- )
- }
- func (a *Auth) checkPublicAccess(path, method string) (bool, error) {
- return a.Enforcer.Enforce(
- systems.GetPlatformMode(),
- "*",
- path,
- method,
- )
- }
复制代码 五、进阶优化建议动态加载策略(支持实时授权变更)通过数据库 adapter: - a.Enforcer, _ = casbin.NewEnforcer(m, xormadapter.NewAdapterByDB(db))
复制代码或使用 API 添加/删除策略: - a.Enforcer.AddPolicy("platform_mode", "admin", "/api/foo", "GET")
- a.Enforcer.RemovePolicy("platform_mode", "admin", "/api/foo", "GET")
复制代码 Redis 缓存策略(性能提升)- watcher, _ := rediswatcher.NewWatcher("127.0.0.1:6379")
- enforcer.SetWatcher(watcher)
复制代码 支持 ABAC 模式(按属性控制)ABAC 模型更细粒度控制,例如: - [request_definition]
- r = sub, obj, act
- [matchers]
- m = r.sub.OrgId == r.obj.OrgId && r.act == p.act
复制代码
六、总结使用 Gin + Casbin 构建 RBAC 系统的关键在于: 合理设计模型与继承关系 灵活匹配 RESTful 路径 支持平台/租户模式 嵌入配置提升部署体验 动态策略 + 缓存优化提升性能
在实际项目中,这套组合不仅功能完整,而且易于维护,值得推荐。
后续计划支持策略在线编辑和管理界面 权限变更自动广播(基于 Redis) 多语言错误提示、精细化返回码
欢迎留言交流,如果你在使用 Gin + Casbin 的过程中遇到问题,或者有更好的改进方案,欢迎在评论区一起探讨! |