Beego 的 Prepare 方法适合放统一鉴权逻辑,需显式 Abort 防止继续执行;RBAC 应在 Filter 阶段完成,注意路径标准化与 HTTP 方法参与判定;静态资源鉴权须用 BeforeStatic;JWT 要防复用、合理设 exp、避免 token 存大量数据。

Beego 的 Prepare 方法适合放统一鉴权逻辑
Prepare 是 Controller 执行前自动调用的方法,天然适合作为登录态校验入口。但要注意它不跳过后续方法——校验失败必须显式 this.Abort("401"),否则会继续执行业务逻辑。
常见错误是把 token 解析和用户查询写在每个 Get/Post 里,导致重复、漏校验、或 Redis 查询不一致。正确做法是:
- 在
controllers/base.go定义BaseController,内嵌beego.Controller,重写Prepare() - 从
this.Ctx.Input.Header("Authorization")提取 token,用gtoken.GfTokenManager.GetTokenData(token)解析(注意:默认用gcache,生产必须切换到 Redis) - 校验通过后存
this.Data["uid"] = uid,后续方法可直接读;失败则this.Abort("401") - 所有业务 Controller 继承
BaseController,无需再手动写校验 - 若接口无需鉴权(如
/v1/auth/login),需在Prepare开头加路径判断,提前 return
Filter 中做 RBAC 权限校验更可靠
Prepare 无法拿到完整路由参数(如 :id)且 POST body 可能已被读取一次,RBAC 校验点应放在 Filter 阶段、Controller 执行前,且必须确保路径标准化。
关键细节:
- 用
strings.TrimSuffix(ctx.Request.URL.Path, "/")统一路径格式,避免/user和/user/被当成两个资源 - HTTP 方法必须参与权限判定:
GET /api/v1/users是user:list,POST /api/v1/users是user:create - 权限表只存
code字段(如user:delete),不硬编码 URL 或 menu_id - 在 Filter 中将请求映射为
resource:action,例如POST /api/v1/orders/:id→order:update - 校验失败用
ctx.StopRun()立即终止,避免后续逻辑执行
静态资源路径的鉴权不能用 BeforeRouter
Beego 对 /static/ 下文件有独立处理流程,默认绕过 BeforeRouter 过滤器。想控制 /static/users/123/private/* 这类路径,必须用 beego.BeforeStatic 时机。
实操要点:
- 注册过滤器时指定
beego.BeforeStatic,不是beego.BeforeRouter - 路由需配合正则匹配,例如
/static/users/:userId([0-9]+)/private/* - 在 Filter 函数中解析
:userId并查会话或 token,校验当前用户是否有权访问该 ID 的私有目录 - 若未登录或无权,直接
ctx.Abort(403),不要依赖Redirect
JWT 鉴权要防 token 复用和过期时间误设
用 jwt-go 实现时,最容易被忽略的是签名密钥管理与时间精度问题。token 一旦签发,服务端无法主动作废(除非引入 Redis 黑名单),所以 exp 必须合理设置。
典型陷阱:
-
claims["exp"]必须用time.Now().Add(...).Unix(),不能手写时间戳或用秒级以外单位 - 客户端传来的
Authorization: Bearer xxx,提取时要strings.Split(authString, " ")判长度和前缀,避免空格截断出错 - 验证失败时别只打日志,必须
this.Abort("401"),否则ServeJSON仍会返回空响应 - 不要在每次请求中调
e.LoadPolicy()—— Casbin 策略应在启动时加载一次,运行时仅用AddPolicy/RemovePolicy增量更新 - JWT 不适合存大量数据,
uid、role、exp足够,权限列表建议查 DB 或缓存,别全塞进 token
BeforeStatic 和 Prepare 的适用边界,很多人直到线上出问题才意识到。


















