在 echo 中写鉴权中间件需定义 echo.middlewarefunc 函数,用 e.use() 挂载;从 authorization header 或 cookie 提取 jwt 并校验 exp/iss;解析后用 c.set("user", &user{}) 透传,下游通过 c.get() 类型断言获取;redis 黑名单校验须加超时与缓存优化。

怎么在 Echo 中写一个能拦截请求的鉴权中间件
Echo 的中间件本质就是一个 echo.MiddlewareFunc 类型的函数,接收 echo.Context,返回 error。它必须在路由注册前用 e.Use() 或 e.Group().Use() 挂载,否则根本不会执行。
常见错误是把鉴权逻辑写成普通 handler(比如直接 e.GET("/admin", authHandler)),结果每次都要重复写校验、没统一出口、也无法提前终止请求。
- 鉴权失败时必须调用
c.NoContent(401)或c.JSON(403, ...),然后立即return,否则后续 handler 仍会执行 - 如果需要透传用户信息给下游 handler,用
c.Set("user_id", uid),别用全局变量或闭包捕获 - 不要在中间件里调用
c.Next()之后再写响应 —— 此时 header 已发,再写 body 会 panic
如何从 Header 或 Cookie 提取 token 并解析 JWT
绝大多数鉴权中间件第一步就是取 token。Echo 不自动解析 Authorization: Bearer xxx,得手动拆;Cookie 更容易漏掉 httpOnly 场景下的读取限制。
典型错误是硬编码 key 名(比如只认 X-Auth-Token),导致前端换 header 就崩;或用 c.QueryParam("token") 做主入口,结果被绕过。
立即学习“go语言免费学习笔记(深入)”;
- 优先从
Authorizationheader 取:正则匹配^Bearer\s+(.+)$,避免手撕字符串 - fallback 到 Cookie 时用
c.Cookie("auth_token"),不是c.Cookies()遍历 —— 性能差且易出错 - JWT 解析务必校验
exp和iss,用github.com/golang-jwt/jwt/v5,别自己 base64 解码后比对字段 - 解析失败要返回具体错误(如
"token expired"),但生产环境别暴露kid或签名算法细节
为什么中间件里调 c.Get("user_id") 总是 nil
因为 c.Set() 写入的数据只在当前 Context 生命周期有效,而中间件和 handler 共享同一个 c 实例 —— 所以不是“没传过去”,而是你读早了或读错了地方。
最常踩的坑是:在中间件里 c.Set("user", u),但在某个 handler 里却写成了 c.Get("user_id")(键名不一致),或者在 c.Next() 之前就读,此时下游还没写入。
- 统一约定 key 名,比如全用
"user",值存结构体指针:&User{ID: 123, Role: "admin"} - 下游 handler 里必须用
v := c.Get("user"); if v != nil { u := v.(*User) },类型断言失败会 panic,加判断 - 别在中间件里用
defer清理c.Set()的值 —— Context 不支持“回滚”,也没必要
并发场景下 Redis 黑名单 token 校验变慢怎么办
当把 token 吊销状态存在 Redis,每次请求都 GET 一次,QPS 上千时延迟飙升,甚至拖垮整个中间件链路。
问题不在 Echo,而在同步阻塞 IO。有人用 redis.Client.Get(ctx, key).Val() 直接卡住 goroutine,等 Redis 返回才继续,这等于把高并发请求串行化了。
- 用
context.WithTimeout包裹 Redis 调用,超时直接放行(或拒绝),别让一个慢查询拖死全部请求 - 考虑本地缓存 + TTL,比如用
groupcache或简单 map +sync.RWMutex缓存最近 1000 个已吊销 token - 更彻底的方案是改用短期 JWT(15 分钟),配合 refresh token 机制,让黑名单检查变成低频操作
- 别在中间件里做耗时 DB 查询 —— 鉴权必须是轻量、快速决策,重逻辑该下沉到业务 handler
真正难的不是写个能跑的中间件,而是让每个环节都扛得住压测、容得下误配、看得清日志 —— 比如 token 解析失败时,c.Logger().Errorf 记哪条字段缺失,比返回 “invalid token” 有用得多。










