根本原因是三元组未对齐策略定义,需将http方法映射为语义动作(如get→read)、路径标准化(去尾斜杠/动态段替换)并启用keymatch2匹配器,否则act或obj不匹配导致静默返回false。

直接在 Gin 中间件里调用 e.Enforce() 很容易漏判或误判,根本原因不是 Casbin 不好用,而是三元组(sub、obj、act)没对齐策略定义——尤其是 act 和 obj 这两块,90% 的权限失效都出在这儿。
为什么 e.Enforce(user, r.URL.Path, r.Method) 总是返回 false?
这不是 Casbin 判错了,是你传进去的 act 和策略里存的不一致。比如前端发的是 GET /api/users/123,你直接传 "GET",但策略里写的是 "read" 或 "user:read",匹配必然失败。
- 必须做 HTTP 方法到语义动作的映射:
map[string]string{"GET": "read", "POST": "create", "PUT": "update", "DELETE": "delete", "PATCH": "update"} -
r.URL.Path不能直接用:它可能带双斜杠(/api//users)、尾部斜杠(/api/users/)、查询参数(?page=1),而策略里写的是/api/users/:id,默认keyMatch不处理这些 - 路径归一化要提前做:
path := strings.TrimRight(r.URL.Path, "/"),再用正则或路由解析器替换动态段(如/users/123→/users/:id) - 模型里必须用
keyMatch2或keyMatch3,别用原始keyMatch;keyMatch2支持:id和*.js这类通配,keyMatch3还支持多级通配(/a/b/c匹配/a/*)
RBAC 角色继承关系为什么加了没生效?
因为你把 g, editor, user 写在代码里调用 e.AddGroupingPolicy(),但没持久化。服务一重启,继承链就没了。
-
g规则不是配置项,是策略数据,必须和p行一样存进 Adapter(数据库或文件);用gorm-adapter就往casbin_rule表插一条ptype='g'的记录 - 检查是否加载成功:调用
e.GetGroupingPolicy(),看返回结果里有没有你加的那条继承关系 - 避免三层以上嵌套(A→B→C→D):Casbin 支持,但匹配耗时随深度指数增长;生产环境建议控制在 2 级以内(例如
admin → editor,editor → user)
Gin 中间件里怎么安全传 sub(用户标识)?
别从 header 取 token 后直接当 sub 用。JWT 解析后应取其中的 role 或 username 字段,而不是原始 token 字符串。
- JWT 校验必须在 Casbin 中间件之前完成,且把解析出的用户角色(如
"admin")存入c.Set("role", role) - Casbin 中间件里用
role, ok := c.Get("role")拿,而不是c.Request.Header.Get("token") - 如果用户有多个角色,
e.Enforce()默认只认一个sub;需要多角色校验就得循环调用,或改用e.EnforceDomain()+ 域模型 - 超级用户(如
root)可加短路逻辑:m = g(r.sub, p.sub) || r.sub == "root",但注意这行要写在模型的[matchers]里,不是中间件里硬判断
最常被忽略的点:路径标准化和动作映射必须在 e.Enforce() 调用前完成,且这两步顺序不能颠倒——先归一化路径,再映射动作,最后喂给 Casbin。任何一步漏掉,策略就形同虚设。











