跳到主要内容

casbin 最佳实践

· 阅读需 17 分钟
ahKevinXy
作者

Casbin是一个强大且高效的开源访问控制库,支持各种访问控制模型,用于在全局范围内执行授权。

执行一组规则就像在策略文件中列出主题、对象和期望的允许操作(或根据您的需要的任何其他格式)一样简单。 这在所有使用Casbin的流程中都是同义的。 开发者/管理员对布局、执行和授权条件的控制是完全的,这些都是通过模型文件设置的。 Casbin提供了一个Enforcer,用于根据提供给Enforcer的策略和模型文件验证传入的请求。

Casbin 是 Go 生态中最主流的开源访问控制框架,支持 RBAC/ABAC/ACL 等多种权限模型,核心优势是「灵活、可扩展、与业务解耦」。下面我会从「核心概念」「最佳实践(代码+规范)」「性能优化」「生产级配置」四个维度,给出能直接落地的 Casbin 最佳实践方案。


1. 核心组件

组件作用
Model权限模型定义(如 RBAC),用 .conf 文件/代码声明规则结构
Policy具体的权限规则(如「用户A可访问资源B」),支持文件/数据库存储
Enforcer核心执行器,加载 Model + Policy,提供 Enforce() 校验权限的核心方法
Adapter策略适配器,负责 Policy 的读写(如 FileAdapter/DBAdapter)
Middleware框架中间件(如 Gin/Echo),用于 HTTP 接口的权限校验

2. 常用模型(优先选 RBAC)

  • RBAC(基于角色的访问控制):最常用,「用户→角色→权限」三层映射,适合大部分业务;
  • ABAC(基于属性的访问控制):灵活,按用户/资源/环境属性判断(如「VIP用户可访问VIP资源」);
  • ACL(访问控制列表):简单,直接「用户→资源→操作」映射,适合简单场景。

二、Casbin 最佳实践(代码+规范)

前置准备

安装依赖:

# 核心库
go get github.com/casbin/casbin/v2
# RBAC 扩展(推荐)
go get github.com/casbin/rbac-model/v2
# 数据库适配器(以 MySQL 为例)
go get github.com/casbin/gorm-adapter/v3
# GORM 依赖(适配 MySQL)
go get gorm.io/gorm gorm.io/driver/mysql

实践 1:规范的 Model 定义(RBAC 为例)

创建 rbac_model.conf(放在 conf/ 目录),遵循「最小权限+清晰分层」原则:

[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]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act # 匹配规则:用户属于角色 + 资源匹配 + 操作匹配

✅ 规范:

  • 模型文件单独存放,不硬编码;
  • 匹配规则(matchers)尽量简洁,避免复杂逻辑(复杂逻辑用 ABAC 或自定义函数);
  • 优先用 some(allow) 规则,符合「白名单」权限设计原则。

实践 2:生产级 Enforcer 初始化(单例+数据库存储)

Casbin Enforcer 是线程安全的,应全局单例初始化,避免重复加载 Model/Policy:

package casbin

import (
"fmt"
"sync"

"github.com/casbin/casbin/v2"
gormadapter "github.com/casbin/gorm-adapter/v3"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)

// 全局单例 Enforcer
var (
enforcer *casbin.Enforcer
once sync.Once
)

// InitEnforcer 初始化 Casbin Enforcer(单例)
func InitEnforcer(dsn string) error {
var err error
once.Do(func() {
// 1. 初始化 GORM 适配器(连接 MySQL,存储 Policy)
adapter, err := gormadapter.NewAdapterByDB(getDB(dsn))
if err != nil {
err = fmt.Errorf("初始化适配器失败:%v", err)
return
}

// 2. 加载 Model 配置 + 初始化 Enforcer
enforcer, err = casbin.NewEnforcer("./conf/rbac_model.conf", adapter)
if err != nil {
err = fmt.Errorf("初始化 Enforcer 失败:%v", err)
return
}

// 3. 自动加载策略(默认开启,可显式调用)
if err = enforcer.LoadPolicy(); err != nil {
err = fmt.Errorf("加载策略失败:%v", err)
return
}
})
return err
}

// getDB 初始化 GORM DB 连接
func getDB(dsn string) *gorm.DB {
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic(fmt.Sprintf("连接数据库失败:%v", err))
}
return db
}

// CheckPermission 校验权限(对外暴露的核心方法)
// sub: 用户ID,obj: 资源(如 "/api/user"),act: 操作(如 "GET")
func CheckPermission(sub, obj, act string) (bool, error) {
if enforcer == nil {
return false, fmt.Errorf("Enforcer 未初始化")
}
// 核心校验方法
return enforcer.Enforce(sub, obj, act)
}

// AddPolicy 添加权限策略
func AddPolicy(sub, obj, act string) error {
_, err := enforcer.AddPolicy(sub, obj, act)
return err
}

// AddRoleForUser 给用户分配角色
func AddRoleForUser(user, role string) error {
_, err := enforcer.AddRoleForUser(user, role)
return err
}

// DeletePolicy 删除权限策略
func DeletePolicy(sub, obj, act string) error {
_, err := enforcer.RemovePolicy(sub, obj, act)
return err
}

✅ 规范:

  • sync.Once 保证 Enforcer 单例,避免重复初始化;
  • 策略存储优先用数据库(而非文件),支持动态更新;
  • 封装通用的权限校验/管理方法,对外屏蔽 Casbin 细节;
  • 初始化失败时 panic/返回错误,避免空指针。

实践 3:Gin 框架中间件(HTTP 接口权限校验)

将权限校验封装为 Gin 中间件,统一拦截接口请求:

package middleware

import (
"net/http"
"strings"

"github.com/gin-gonic/gin"
"your-project-path/casbin"
)

// CasbinMiddleware Casbin 权限校验中间件
func CasbinMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 1. 获取当前用户(从 Token/Context 中解析,示例用固定值,需替换为真实逻辑)
userId := c.GetHeader("X-User-ID")
if userId == "" {
c.JSON(http.StatusUnauthorized, gin.H{"msg": "未登录"})
c.Abort()
return
}

// 2. 获取请求资源和操作
// 资源:请求路径(如 "/api/user/123" → "/api/user",可根据业务简化)
obj := strings.TrimSuffix(c.Request.URL.Path, "/")
// 操作:HTTP 方法(GET/POST/PUT/DELETE)
act := c.Request.Method

// 3. 校验权限
ok, err := casbin.CheckPermission(userId, obj, act)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"msg": "权限校验失败:" + err.Error()})
c.Abort()
return
}
if !ok {
c.JSON(http.StatusForbidden, gin.H{"msg": "无权限访问"})
c.Abort()
return
}

// 4. 权限通过,继续执行
c.Next()
}
}

使用中间件:

func main() {
r := gin.Default()

// 初始化 Casbin
_ = casbin.InitEnforcer("root:123456@tcp(127.0.0.1:3306)/casbin?charset=utf8mb4")

// 全局中间件(所有接口都校验)
// r.Use(middleware.CasbinMiddleware())

// 或针对特定路由组校验
apiGroup := r.Group("/api")
apiGroup.Use(middleware.CasbinMiddleware())
{
apiGroup.GET("/user", func(c *gin.Context) {
c.JSON(200, gin.H{"msg": "访问用户列表成功"})
})
apiGroup.POST("/user", func(c *gin.Context) {
c.JSON(200, gin.H{"msg": "创建用户成功"})
})
}

r.Run(":8080")
}

✅ 规范:

  • 资源/操作的定义要统一(如路径简化、HTTP 方法标准化);
  • 中间件中先校验用户是否登录,再校验权限;
  • 权限失败时返回 403,系统错误返回 500,语义清晰;
  • 可针对路由组单独配置中间件,避免全局拦截无需权限的接口(如登录/注册)。

实践 4:动态更新策略(无需重启服务)

业务中权限变更(如给用户分配角色)后,需实时加载最新策略:

// 场景:后台修改用户权限后,主动刷新策略
func RefreshPolicy() error {
return enforcer.LoadPolicy()
}

// 或开启自动刷新(定时加载,适合策略变更不频繁的场景)
func AutoRefreshPolicy(interval time.Duration) {
ticker := time.NewTicker(interval)
defer ticker.Stop()
for range ticker.C {
if err := enforcer.LoadPolicy(); err != nil {
fmt.Printf("自动刷新策略失败:%v\n", err)
}
}
}

// 启动自动刷新(示例:每5分钟刷新一次)
// go AutoRefreshPolicy(5 * time.Minute)

✅ 规范:

  • 策略变更后必须调用 LoadPolicy(),否则 Enforcer 仍使用缓存的策略;
  • 高频变更场景:主动调用 LoadPolicy()
  • 低频变更场景:定时自动刷新,减少数据库压力。

三、性能优化(生产级必备)

1. 策略缓存(核心优化)

Casbin 默认每次 Enforce() 都会查询数据库,高并发下性能差,需加缓存:

package casbin

import (
"sync"
"time"

"github.com/patrickmn/go-cache"
)

// 新增缓存层
var (
permCache *cache.Cache
cacheOnce sync.Once
)

// 初始化缓存(过期时间 5 分钟,清理间隔 10 分钟)
func initCache() {
cacheOnce.Do(func() {
permCache = cache.New(5*time.Minute, 10*time.Minute)
})
}

// CheckPermissionWithCache 带缓存的权限校验
func CheckPermissionWithCache(sub, obj, act string) (bool, error) {
if enforcer == nil {
return false, fmt.Errorf("Enforcer 未初始化")
}

// 1. 构造缓存 key
cacheKey := fmt.Sprintf("%s:%s:%s", sub, obj, act)

// 2. 查缓存
if val, ok := permCache.Get(cacheKey); ok {
return val.(bool), nil
}

// 3. 缓存未命中,查 Casbin
ok, err := enforcer.Enforce(sub, obj, act)
if err != nil {
return false, err
}

// 4. 写入缓存
permCache.Set(cacheKey, ok, cache.DefaultExpiration)
return ok, nil
}

// 权限变更时清理缓存
func ClearPermissionCache(sub, obj, act string) {
cacheKey := fmt.Sprintf("%s:%s:%s", sub, obj, act)
permCache.Delete(cacheKey)
}

✅ 效果:高并发下(QPS 1000+),缓存可将权限校验耗时从 10ms+ 降到 1ms 内。

2. 批量校验(减少数据库查询)

批量校验多个权限时,一次性加载策略后本地校验:

// BatchCheckPermissions 批量校验权限
func BatchCheckPermissions(sub string, reqs [][2]string) (map[string]bool, error) {
// 一次性加载所有策略
if err := enforcer.LoadPolicy(); err != nil {
return nil, err
}

result := make(map[string]bool)
for _, req := range reqs {
obj, act := req[0], req[1]
key := fmt.Sprintf("%s:%s", obj, act)
result[key], _ = enforcer.Enforce(sub, obj, act)
}
return result, nil
}

// 使用示例
// reqs := [][2]string{{"/api/user", "GET"}, {"/api/order", "POST"}}
// res, _ := BatchCheckPermissions("user1", reqs)

3. 数据库优化

  • 给 Casbin 策略表(casbin_rule)加索引:
    CREATE INDEX idx_casbin_sub_obj_act ON casbin_rule (v0, v1, v2);
  • 用连接池管理数据库连接,避免频繁创建/销毁连接;
  • 策略表分表(超大规模场景,如百万级策略):按 v0(用户/角色)分表。

四、生产级避坑指南

1. 避免硬编码策略

  • 错误:代码中直接写死 AddPolicy("user1", "/api/user", "GET")
  • 正确:权限策略通过后台系统配置、导入导出等方式管理,代码仅提供接口。

2. 最小权限原则

  • 给角色/用户分配权限时,只给「必要的权限」,避免过度授权;
  • 示例:普通用户仅能 GET /api/user,管理员才能 POST/PUT/DELETE /api/user

3. 审计日志

记录所有权限相关操作,便于追溯问题:

// 封装策略操作方法,添加日志
func AddPolicyWithLog(sub, obj, act string, operator string) error {
// 1. 记录日志
fmt.Printf("用户 %s 给 %s 添加了 %s:%s 的权限\n", operator, sub, obj, act)
// 2. 执行操作
return AddPolicy(sub, obj, act)
}

4. 避免循环角色继承

RBAC 中角色继承(如 g(user1, role1), g(role1, role2))不要形成循环,否则会导致 Enforce() 死循环。

5. 测试覆盖

对权限校验逻辑写单元测试,覆盖「允许/拒绝/边界场景」:

func TestCheckPermission(t *testing.T) {
// 初始化测试 Enforcer(用内存适配器,避免污染生产数据)
adapter := gormadapter.NewAdapter("mysql", "root:123456@tcp(127.0.0.1:3306)/casbin_test?charset=utf8mb4", true)
e, _ := casbin.NewEnforcer("./conf/rbac_model.conf", adapter)

// 测试用例
tests := []struct {
name string
sub string
obj string
act string
want bool
wantErr bool
}{
{"管理员可访问用户列表", "admin", "/api/user", "GET", true, false},
{"普通用户不可修改用户", "user1", "/api/user", "PUT", false, false},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := e.Enforce(tt.sub, tt.obj, tt.act)
if (err != nil) != tt.wantErr {
t.Errorf("Enforce() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("Enforce() got = %v, want %v", got, tt.want)
}
})
}
}

五、总结

  1. 核心规范:Enforcer 单例初始化、策略用数据库存储、封装通用权限方法,对外屏蔽 Casbin 细节;
  2. 性能优化:加权限缓存(核心)、批量校验、数据库索引,高并发下必须做;
  3. 工程化:用中间件统一校验 HTTP 接口权限,权限变更时刷新策略+清理缓存;
  4. 安全原则:最小权限、审计日志、测试覆盖,避免过度授权和逻辑漏洞。

在 Gin 框架中集成 Casbin 中间件是实现接口权限校验的标准方式,核心思路是通过中间件拦截请求→解析用户/资源/操作→调用 Casbin 校验权限。下面我会给出「完整可运行的代码 + 分步讲解 + 最佳实践」,新手也能直接落地。


一、前置准备

1. 安装依赖

# Gin 框架
go get github.com/gin-gonic/gin
# Casbin 核心库
go get github.com/casbin/casbin/v2
# Casbin + GORM 适配器(MySQL 存储策略,生产首选)
go get github.com/casbin/gorm-adapter/v3
# GORM + MySQL 驱动
go get gorm.io/gorm gorm.io/driver/mysql

2. 核心概念约定

在 Gin 中使用 Casbin,需先统一「用户、资源、操作」的定义规则:

要素取值来源(示例)说明
用户(sub)请求头 X-User-ID(如 user_123登录用户的唯一标识(从 Token/JWT 解析)
资源(obj)请求路径(如 /api/user简化路径(去掉参数,如 /api/user/123/api/user
操作(act)HTTP 方法(GET/POST/PUT/DELETE)对应接口的操作类型

二、完整实现步骤

步骤 1:初始化 Casbin(全局单例)

封装 Casbin 初始化逻辑,保证全局唯一 Enforcer,避免重复加载策略。

// pkg/casbin/casbin.go
package casbin

import (
"fmt"
"sync"

"github.com/casbin/casbin/v2"
gormadapter "github.com/casbin/gorm-adapter/v3"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)

// 全局 Enforcer 单例
var (
enforcer *casbin.Enforcer
once sync.Once
)

// InitCasbin 初始化 Casbin Enforcer
// dsn: MySQL 连接串(如 root:123456@tcp(127.0.0.1:3306)/casbin?charset=utf8mb4)
// modelPath: Casbin 模型配置文件路径(如 ./conf/rbac_model.conf)
func InitCasbin(dsn, modelPath string) error {
var err error
once.Do(func() {
// 1. 初始化 GORM 连接
db, dbErr := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if dbErr != nil {
err = fmt.Errorf("连接数据库失败:%v", dbErr)
return
}

// 2. 创建 Casbin MySQL 适配器
adapter, adapterErr := gormadapter.NewAdapterByDB(db)
if adapterErr != nil {
err = fmt.Errorf("初始化 Casbin 适配器失败:%v", adapterErr)
return
}

// 3. 加载模型 + 初始化 Enforcer
enforcer, err = casbin.NewEnforcer(modelPath, adapter)
if err != nil {
err = fmt.Errorf("初始化 Enforcer 失败:%v", err)
return
}

// 4. 加载策略(从数据库读取权限规则)
if loadErr := enforcer.LoadPolicy(); loadErr != nil {
err = fmt.Errorf("加载权限策略失败:%v", loadErr)
return
}
})
return err
}

// CheckPermission 校验权限
// sub: 用户ID,obj: 资源路径,act: 操作(HTTP方法)
func CheckPermission(sub, obj, act string) (bool, error) {
if enforcer == nil {
return false, fmt.Errorf("Casbin Enforcer 未初始化")
}
return enforcer.Enforce(sub, obj, act)
}

// --------------- 可选:权限管理方法(增删角色/策略)---------------
// AddRoleForUser 给用户分配角色
func AddRoleForUser(user, role string) error {
_, err := enforcer.AddRoleForUser(user, role)
return err
}

// AddPolicy 添加权限策略
func AddPolicy(sub, obj, act string) error {
_, err := enforcer.AddPolicy(sub, obj, act)
return err
}

步骤 2:编写 Casbin 模型配置(RBAC)

创建 conf/rbac_model.conf 文件,定义 RBAC 权限模型(最常用):

[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

步骤 3:实现 Gin Casbin 中间件

封装中间件,统一拦截请求并校验权限,处理「未登录、无权限、系统错误」等场景。

// pkg/middleware/casbin.go
package middleware

import (
"net/http"
"strings"

"github.com/gin-gonic/gin"
"your-project-path/pkg/casbin" // 替换为你的实际路径
)

// CasbinMiddleware Gin Casbin 权限校验中间件
func CasbinMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 1. 解析当前用户(核心:替换为你的真实登录态解析逻辑)
// 示例:从请求头获取用户ID,实际项目中从 JWT/Token 解析
userId := c.GetHeader("X-User-ID")
if userId == "" {
c.JSON(http.StatusUnauthorized, gin.H{
"code": 401,
"msg": "未登录,请先登录",
})
c.Abort() // 终止请求链
return
}

// 2. 解析请求资源(简化路径,去掉参数)
// 示例:/api/user/123 → /api/user;/api/order?page=1 → /api/order
obj := strings.TrimSuffix(c.Request.URL.Path, "/")
// 可选:去掉路径中的数字参数(适配 RESTful 接口)
// obj = regexp.MustCompile(`/\d+`).ReplaceAllString(obj, "")

// 3. 解析操作(HTTP 方法)
act := c.Request.Method

// 4. 调用 Casbin 校验权限
ok, err := casbin.CheckPermission(userId, obj, act)
if err != nil {
// 系统错误:返回 500
c.JSON(http.StatusInternalServerError, gin.H{
"code": 500,
"msg": "权限校验失败:" + err.Error(),
})
c.Abort()
return
}

// 5. 无权限:返回 403
if !ok {
c.JSON(http.StatusForbidden, gin.H{
"code": 403,
"msg": "无权限访问该接口",
})
c.Abort()
return
}

// 6. 权限通过:继续执行后续处理
c.Next()
}
}

步骤 4:在 Gin 中集成中间件

主程序中初始化 Casbin,并将中间件应用到路由(全局/路由组)。

// main.go
package main

import (
"fmt"

"github.com/gin-gonic/gin"
"your-project-path/pkg/casbin"
"your-project-path/pkg/middleware"
)

func main() {
// 1. 初始化 Gin
r := gin.Default()

// 2. 初始化 Casbin(替换为你的 MySQL 连接串和模型路径)
dsn := "root:123456@tcp(127.0.0.1:3306)/casbin?charset=utf8mb4&parseTime=True&loc=Local"
if err := casbin.InitCasbin(dsn, "./conf/rbac_model.conf"); err != nil {
panic(fmt.Sprintf("Casbin 初始化失败:%v", err))
}

// 3. 初始化测试权限(仅测试用,生产从数据库配置)
_ = casbin.AddPolicy("admin", "/api/user", "GET") // admin 可 GET /api/user
_ = casbin.AddPolicy("user1", "/api/user", "GET") // user1 可 GET /api/user
_ = casbin.AddPolicy("admin", "/api/user", "POST") // admin 可 POST /api/user

// 4. 应用中间件
// 方式1:全局中间件(所有接口都校验)
// r.Use(middleware.CasbinMiddleware())

// 方式2:路由组中间件(推荐,仅校验需要权限的接口)
apiGroup := r.Group("/api")
apiGroup.Use(middleware.CasbinMiddleware())
{
apiGroup.GET("/user", func(c *gin.Context) {
c.JSON(200, gin.H{
"code": 200,
"msg": "访问用户列表成功",
})
})
apiGroup.POST("/user", func(c *gin.Context) {
c.JSON(200, gin.H{
"code": 200,
"msg": "创建用户成功",
})
})
}

// 5. 无需权限的接口(如登录/注册)
r.POST("/login", func(c *gin.Context) {
c.JSON(200, gin.H{
"code": 200,
"msg": "登录成功",
"data": gin.H{"userId": "admin"}, // 示例返回用户ID
})
})

// 启动服务
_ = r.Run(":8080")
}

三、测试验证

1. 测试有权限的请求

# admin 访问 GET /api/user(允许)
curl -H "X-User-ID: admin" http://localhost:8080/api/user
# 响应:{"code":200,"msg":"访问用户列表成功"}

# admin 访问 POST /api/user(允许)
curl -X POST -H "X-User-ID: admin" http://localhost:8080/api/user
# 响应:{"code":200,"msg":"创建用户成功"}

2. 测试无权限的请求

# user1 访问 POST /api/user(拒绝)
curl -X POST -H "X-User-ID: user1" http://localhost:8080/api/user
# 响应:{"code":403,"msg":"无权限访问该接口"}

3. 测试未登录的请求

# 无 X-User-ID 头
curl http://localhost:8080/api/user
# 响应:{"code":401,"msg":"未登录,请先登录"}

四、最佳实践与优化

1. 登录态解析优化

实际项目中,用户ID需从 JWT Token 解析(而非请求头),示例:

// 在中间件中解析 JWT
token := c.GetHeader("Authorization")
if token == "" {
c.JSON(401, gin.H{"msg": "缺少Token"})
c.Abort()
return
}
// 解析 Token 获取 userId(替换为你的 JWT 解析逻辑)
userId, err := ParseJWT(token)
if err != nil {
c.JSON(401, gin.H{"msg": "Token无效"})
c.Abort()
return
}

2. 性能优化(缓存)

高并发场景下,给权限校验加缓存(避免每次查数据库):

// pkg/casbin/casbin.go 中新增缓存逻辑
import (
"time"
"github.com/patrickmn/go-cache"
)

var permCache = cache.New(5*time.Minute, 10*time.Minute)

// CheckPermissionWithCache 带缓存的权限校验
func CheckPermissionWithCache(sub, obj, act string) (bool, error) {
// 1. 查缓存
key := fmt.Sprintf("%s:%s:%s", sub, obj, act)
if val, ok := permCache.Get(key); ok {
return val.(bool), nil
}
// 2. 查 Casbin
ok, err := enforcer.Enforce(sub, obj, act)
if err != nil {
return false, err
}
// 3. 写缓存
permCache.Set(key, ok, cache.DefaultExpiration)
return ok, nil
}

3. 忽略无需权限的路径

在中间件中跳过静态文件、健康检查等接口:

// 无需权限的路径列表
ignorePaths := []string{"/health", "/static/", "/login"}
// 检查是否需要忽略
for _, path := range ignorePaths {
if strings.HasPrefix(c.Request.URL.Path, path) {
c.Next()
return
}
}

4. 动态刷新权限策略

权限变更后(如后台修改权限),需手动刷新策略:

// 新增刷新方法
func RefreshPolicy() error {
return enforcer.LoadPolicy()
}

// 权限变更时调用
// _ = casbin.RefreshPolicy()

总结

  1. 核心流程:初始化 Casbin 单例 → 编写中间件解析用户/资源/操作 → 调用 CheckPermission 校验 → 拦截无权限请求;
  2. 关键优化:生产环境需加权限缓存、解析 JWT 登录态、忽略无需权限的路径;
  3. 最佳实践:中间件只做权限校验,不侵入业务逻辑;策略存储用数据库,支持动态更新;遵循「最小权限原则」分配权限。