Go语言开发:利用Gin和Casbin设计现代化RBAC权限体系

基于角色(RBAC)实现 RESTful API 权限控制:Gin + Casbin 方案

在构建高效、安全的 RESTful API 时,权限控制至关重要。基于角色的访问控制(RBAC)是当前广泛采用的权限管理机制。本文将介绍如何使用 GinCasbin 结合实现一个完整的 RBAC 权限控制方案,并展示具体的实现步骤。


1. 需求分析

在设计一个标准的权限管理系统时,我们需要解决以下几个关键问题:

  1. 角色继承关系
    管理不同角色之间的继承关系,确保权限的层级关系。
  2. RESTful API 的路径匹配
    能够灵活地匹配 RESTful 路径,支持动态参数。
  3. HTTP 方法级别的控制
    控制对不同 HTTP 方法(如 GET、POST)的访问权限。
  4. 平台模式支持
    支持单租户和多租户模式,确保权限控制可以跨平台使用。

Casbin 是一个功能强大的权限管理框架,完美地满足了上述需求。通过 Casbin,我们可以轻松地实现细粒度的权限控制。


2. Casbin 模型定义

在 Casbin 中,权限模型是权限控制的核心。首先,我们来看看 Casbin 的基本模型定义:

[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:表示平台模式(如单租户或多租户)。
  • subobjact:分别表示角色、资源和操作。
  • keyMatch2:实现了 RESTful 路径的匹配。
  • 通配符 *:用于简化权限配置,可以批量授权。

3. 权限规则配置

在定义了权限模型之后,接下来需要配置具体的权限规则。以下是一些常见的权限规则配置示例:

# 角色继承
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

4. Go 代码实现

4.1 嵌入配置文件

为了便于管理配置文件,我们将 Casbin 的模型和策略文件嵌入到 Go 代码中:

package routers

import "embed"

//go:embed model.conf policy.csv
var fs embed.FS

func MustAssetString(name string) string {
    s, err := fs.ReadFile(name)
    if err != nil {
        panic(err)
    }
    return string(s)
}

4.2 实现认证中间件

在 Gin 中实现认证中间件:

type Auth struct {
    Enforcer *casbin.Enforcer
}

func NewAuth() *Auth {
    m := model.NewModel()
    err := m.LoadModelFromText(routers.MustAssetString("model.conf"))
    if err != nil {
        logrus.Panicf("load casbin model failed: %v", err)
    }

    enforcer, err := casbin.NewEnforcer(m, textadapter.NewAdapter(routers.MustAssetString("policy.csv")))
    if err != nil {
        logrus.Panicf("new enforcer failed: %v", err)
    }

    return &Auth{Enforcer: enforcer}
}

4.3 权限验证逻辑

在中间件中实现权限验证:

func (a *Auth) HandlerFunc() gin.HandlerFunc {
    return func(c *gin.Context) {
        user, valid, err := a.validateByAuthorization(c)
        if err != nil {
            c.Render(err)
            c.Abort()
            return
        }

        if !valid {
            user, valid, err = a.validateByCookie(c)
            if err != nil {
                c.Render(err)
                c.Abort()
                return
            }
        }

        // 权限检查
        if valid {
            if ok, _ := a.checkPermission(user, c.Request.URL.Path, c.Request.Method); ok {
                c.Next()
                return
            }
        } else {
            if ok, _ := a.checkPublicAccess(c.Request.URL.Path, c.Request.Method); ok {
                c.Next()
                return
            }
        }

        c.Render(401)
        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,
    )
}

5. 小技巧

  • 嵌入配置文件:使用 embed 将配置文件编译进二进制,避免部署时的文件管理问题。
  • 公共接口优化:在权限检查前,先判断是否为公共接口,减少无效的权限查询。
  • 角色继承:利用角色继承来简化权限配置,特别是在多角色的场景下。
  • 路径参数匹配:使用 keyMatch2 来匹配 RESTful API 中的路径参数(例如 /users/:id)。

6. 总结

通过结合 CasbinGin,我们可以构建一个高效且灵活的 RBAC 权限控制系统。关键要点包括:

  • 设计合理的权限模型,支持角色继承。
  • 使用 Casbin 实现灵活的权限管理和验证。
  • 通过 Gin 中间件将权限验证与请求处理结合,确保系统的安全性和可维护性。

后续,也可计划在此基础上添加 Redis 缓存支持,并支持动态更新权限规则功能。

THE END