Casbin的Enforce()参数必须严格按model.conf中r = sub, obj, act顺序传入:sub为角色ID(非用户名),obj为去前缀路径(如v1/user),act为大写HTTP方法(如"GET")。

AuthMiddleware 里怎么传角色参数才不踩坑
直接在中间件里硬编码 requiredRole 是最常见也最容易出问题的做法——比如超管要访问普通接口时被拦住,或者多个角色共用同一接口却只能写死一个值。
真正可行的方式是把角色判断逻辑从中间件里抽出来,让路由层决定「谁有资格进」,而不是让中间件自己猜。比如:
-
AuthMiddleware只负责解析 JWT、提取claims["role"]并塞进c上下文,不做任何判断 - 后续中间件(如
RoleCheckMiddleware)或 handler 自己调用checkPermission(role, path, method)做动态校验 - 避免在
AuthMiddleware里写if userRole != "admin"这类固定分支,它不该承担授权决策职责
用 Casbin 做 RBAC 时,e.Enforce() 的三个参数怎么填才对
很多人卡在 sub、obj、act 到底该传什么——填错一个,整个权限就失效,但错误信息又不报具体哪错了。
对照 gin-vue-admin 实际用法:
-
sub是用户所属角色 ID(不是用户名,也不是字符串 "admin"),通常来自claims["authority_id"]或数据库查出的role_id -
obj是请求路径去掉前缀后的结果,比如/api/v1/user→v1/user(注意不是完整 URL,也不带 HTTP 方法) -
act就是c.Request.Method,全大写,如"GET"、"POST" - Casbin 模型文件(
rbac_model.conf)里必须和这三者顺序、语义严格匹配,否则e.Enforce()永远返回false
按钮级权限为什么不能只靠后端拦截
后端用 Casbin 拦 /api/v1/user/delete 是对的,但前端按钮显示逻辑如果只依赖「调接口失败再隐藏」,会导致 UX 断层:按钮先闪一下再消失,或点击后才弹“权限不足”。
真正落地的做法是前后端协同:
- 登录后,后端一次性返回当前角色拥有的全部按钮权限列表,格式如
["user_add", "user_edit", "menu_export"] - 前端用这个列表做 v-if / directive 控制按钮显隐,不是靠接口响应状态
- 按钮 key(如
user_delete)必须和后端 Casbin 策略里的obj字段一致,否则策略白配 - 别漏掉 GET 类按钮(如详情页“导出”),它们对应的是
GET请求,不是POST
gin-jwt 的 Authorizer 函数容易忽略的执行时机
Authorizer 不是在每次请求都执行,而只在 JWT 解析成功、签名有效、未过期的前提下才触发——这意味着它不会捕获 token 不存在、格式错误、过期等前置问题。
所以实际使用中:
- 不要指望
Authorizer处理所有权限异常,它只管「合法用户有没有权」,不管「用户有没有登录」 - 必须配合
LoginHandler和MiddlewareFunc的完整链路,否则Authorizer根本不会跑 - 里面取
claims["role"]时一定要做类型断言判断,claims["role"].(string)在 claims 为空或字段缺失时会 panic - 路径匹配建议用
strings.HasPrefix(c.Request.URL.Path, "/admin")而不是==,否则带 query 参数的请求会误判


















