Iris的iris.Context不能直接用net/http中间件,因其上下文封装与标准http.Handler不兼容;需编写接受iris.Context的专用中间件,并通过ctx.Values()安全透传用户信息,校验通过后必须调用ctx.Next()继续执行链。

为什么 Iris 的 iris.Context 不能直接用 net/http 的中间件
因为 Iris 自带的请求生命周期和上下文封装(iris.Context)与标准 http.Handler 不兼容。你如果把一个接收 http.HandlerFunc 的认证函数(比如基于 jwt-go 写的)直接传给 app.Use(),会编译失败或 panic —— iris.Context 不是 http.ResponseWriter 和 *http.Request 的简单组合,它有自己的一套方法链(如 ctx.StatusCode()、ctx.Values().Set())。
正确做法是写一个接受 iris.Context 的函数,并在其中完成 token 解析、校验、挂载用户信息等逻辑:
func AuthMiddleware() iris.Handler {
return func(ctx iris.Context) {
authHeader := ctx.GetHeader("Authorization")
if authHeader == "" {
ctx.StatusCode(iris.StatusUnauthorized)
ctx.JSON(iris.Map{"error": "missing Authorization header"})
return
}
tokenStr := strings.TrimPrefix(authHeader, "Bearer ")
if tokenStr == authHeader { // 没有 Bearer 前缀
ctx.StatusCode(iris.StatusUnauthorized)
ctx.JSON(iris.Map{"error": "invalid auth format"})
return
}
token, err := jwt.Parse(tokenStr, func(t *jwt.Token) (interface{}, error) {
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
}
return []byte("your-secret-key"), nil
})
if err != nil || !token.Valid {
ctx.StatusCode(iris.StatusUnauthorized)
ctx.JSON(iris.Map{"error": "invalid or expired token"})
return
}
// 假设 payload 里有 user_id 字段
if claims, ok := token.Claims.(jwt.MapClaims); ok && claims["user_id"] != nil {
ctx.Values().Set("user_id", int64(claims["user_id"].(float64)))
} else {
ctx.StatusCode(iris.StatusUnauthorized)
ctx.JSON(iris.Map{"error": "malformed token claims"})
return
}
ctx.Next() // 继续后续 handler
}
}
如何让认证中间件支持可选路由(比如登录接口本身不校验)
Iris 不提供“跳过中间件”的内置语法,但你可以用 ctx.GetCurrentRoute().Name() 或路径前缀做白名单判断,更推荐用路由分组 + 中间件绑定粒度控制:
- 把需要认证的路由全部注册在
authRouter := app.Party("/api")下,再对这个 group 调用.Use(AuthMiddleware()) - 把登录、注册等公开接口放在根 router 或另一个
publicRouter := app.Party("/auth")下,不加中间件 - 避免在中间件里硬编码路径字符串(比如
if ctx.Path() == "/login" { return }),容易漏匹配或和路由参数冲突
如果你必须在一个 handler 上动态跳过(比如某些 GET 接口允许匿名),可以在中间件里检查 ctx.GetCurrentRoute().GetHandlers() 或提前用 ctx.Values().Set("skip_auth", true) 在前置 handler 中标记,但这种模式易出错,不推荐。
为什么解析 JWT 后要调用 ctx.Next() 而不是 return
ctx.Next() 是 Iris 中间件链的核心机制:它把控制权交给下一个 handler(可能是另一个中间件,也可能是最终业务 handler)。如果校验通过后直接 return,后续所有 handler 都不会执行,API 就卡住了。
常见错误包括:
- 忘记
ctx.Next()→ 所有被保护路由返回空响应或超时 - 在错误分支里漏掉
return→ 错误响应发出后仍继续执行ctx.Next(),导致 panic(例如向已写出状态码的 response 再写 JSON) - 把
ctx.Next()放在 defer 里 → 执行顺序错乱,可能在错误处理前就跳转了
务必保证:每个分支(成功/失败)都有明确的终止逻辑 —— 成功走 ctx.Next(),失败走 ctx.StatusCode() + ctx.JSON() + return。
如何安全地把用户信息从中间件透传到 handler
别用全局变量或闭包捕获,Iris 提供了线程安全的 ctx.Values(),本质是一个 sync.Map 包装的键值容器,生命周期与当前请求一致:
- 在中间件中存:
ctx.Values().Set("user_id", 123)或ctx.Values().Set("user", userStruct) - 在 handler 中取:
if uid, ok := ctx.Values().Get("user_id").(int64); ok { ... } - 避免用
ctx.Values().GetString("user_id")这类强制转换,类型不匹配会 panic;优先用Get()+ 类型断言 - 不要往
ctx.Values()存闭包、未导出 struct 或含指针的复杂对象,除非你清楚其生命周期和并发安全性
如果项目中认证逻辑变复杂(比如需查 DB 校验 token 黑名单),建议把解析和校验拆成独立函数,中间件只负责调用并处理流程分支 —— 这样单元测试和复用都更容易。
JWT 密钥硬编码、未验证 exp 字段、忽略 iat 和 nbf、用 HS256 却泄露密钥,这些都不是 Iris 特有的问题,但会在中间件里集中暴露。认证中间件看似几行代码,真正的复杂点永远在边界条件和安全假设上。


















