权限中间件必须在路由注册前挂载,Iris 的 Use 和 UseGlobal 需置于 Get/Post 等之前,否则不生效;Use 作用于后续路由,UseGlobal 影响全部路由;校验 Token 需严格解析 Authorization Header、防 alg=none 攻击、精确比对权限;用户信息通过 ctx.Values() 透传,避免敏感字段;测试需覆盖空/超长 token、exp 校验及时区一致性、panic 日志兜底。

权限中间件必须在路由注册前挂载
中间件不会自动生效,Iris 的 Use 和 UseGlobal 必须在 Get、Post 等路由注册之前调用,否则请求根本不会经过它。常见错误是把中间件写在所有 app.Get(...) 之后,结果形同虚设。
正确顺序示例:
app := iris.New()
app.Use(authMiddleware) // ✅ 必须放这里
app.Get("/admin", adminHandler)
app.Post("/api/user", userCreateHandler)
-
Use只影响后续注册的路由(按代码顺序) -
UseGlobal影响所有路由,包括后续动态注册的,但会增加无关路径的开销 - 若只保护部分路由组,优先用
app.Party("/admin").Use(authMiddleware)
从 Context 提取并校验 Token 的典型流程
Iris 中权限验证通常依赖 Authorization Header 中的 Bearer Token,中间件需手动解析、校验签名、检查过期和权限字段。别直接信任 ctx.GetHeader("Authorization") 的原始值——它可能为空、格式错误或被篡改。
关键步骤:
- 用
strings.HasPrefix(auth, "Bearer ")判断前缀,再用strings.TrimPrefix(auth, "Bearer ")提取 token 字符串 - 调用 JWT 库(如
github.com/golang-jwt/jwt/v5)解析时,务必传入自定义jwt.WithValidMethods([]string{jwt.SigningMethodHS256.Alg()})防止 alg=none 攻击 - 校验
Claims["permissions"]或Claims["role"]时,建议用字符串切片比对,而非模糊匹配(如避免strings.Contains(perm, "admin"))
示例片段(不包含 JWT 解析细节,聚焦 Iris 上下文交互):
func authMiddleware(ctx iris.Context) {
auth := ctx.GetHeader("Authorization")
if !strings.HasPrefix(auth, "Bearer ") {
ctx.StatusCode(iris.StatusUnauthorized)
ctx.JSON(iris.Map{"error": "missing or malformed authorization header"})
return
}
tokenStr := strings.TrimPrefix(auth, "Bearer ")
claims, err := parseAndValidateToken(tokenStr) // 你自己的函数
if err != nil {
ctx.StatusCode(iris.StatusUnauthorized)
ctx.JSON(iris.Map{"error": "invalid token"})
return
}
if !hasPermission(claims, "admin:delete") {
ctx.StatusCode(iris.StatusForbidden)
ctx.JSON(iris.Map{"error": "insufficient permissions"})
return
}
ctx.Next() // ✅ 记得放行
}
如何向下游 Handler 透传用户权限信息
权限中间件本身不改变请求逻辑,但 Handler 往往需要知道当前用户是谁、有哪些权限。Iris 不提供类似 Express 的 res.locals,必须显式存取。
- 用
ctx.Values().Set("user_id", userID)存储结构化数据,下游用ctx.Values().Get("user_id")取出(注意类型断言) - 避免存敏感字段(如原始 token、密码哈希),只存必要 ID 和权限列表
- 如果 Handler 需要频繁访问,可封装一个辅助方法:
func GetUserID(ctx iris.Context) (int64, bool) { ... } - 不要用
ctx.SetUserValues——它是为 Session 设计的,且 key 冲突风险高
下游 Handler 示例:
func adminDeleteHandler(ctx iris.Context) {
userID, ok := ctx.Values().Get("user_id").(int64)
if !ok {
ctx.StatusCode(iris.StatusInternalServerError)
return
}
// 继续业务逻辑...
}
测试中间件时容易忽略的边界情况
本地跑通不代表线上安全。真实环境里,这些点常被跳过:
- 未处理空 token 或超长 token(可能导致 panic 或 DoS),应在解析前加长度限制(如
if len(tokenStr) > 512) - 忘记校验
exp字段,导致过期 token 仍被接受 - 使用
time.Now().Unix()校验时间,但 JWT 库默认用time.Now().UTC(),时区不一致会导致误判 - 中间件 panic 后 Iris 默认返回 500,但没记录日志——建议在中间件最外层加
defer捕获并打印
最简日志兜底:
func authMiddleware(ctx iris.Context) {
defer func() {
if r := recover(); r != nil {
app.Logger().Errorf("auth middleware panic: %v", r)
ctx.StatusCode(iris.StatusInternalServerError)
}
}()
// ...原有逻辑
}
权限逻辑越靠前,出错代价越小;但越复杂,漏掉的边界就越隐蔽。JWT 解析、角色继承、RBAC 规则加载这些,都不该塞进中间件主体里——拆成独立函数,才好单元测试。











