Echo框架无内置BearerAuth中间件,必须手动实现:解析Authorization头、安全提取Bearer后token、JWT签名与过期校验、结果存入c.Set(),并确保注册顺序在CORS之后。

Bearer Token校验中间件必须手动实现
Echo框架没有内置的 BearerAuth 中间件,middleware.BasicAuth 和 middleware.KeyAuth 都不适用于标准的 Authorization: Bearer xxx 场景。你必须自己写一个解析和校验逻辑的中间件,否则请求会直接绕过认证或返回 401 但原因不明确。
常见错误现象包括:
- 前端传了
Authorization: Bearer eyJhb...,后端却读不到 —— 因为没正确拆分Bearer前缀 - Token 校验通过但后续 handler 拿不到用户信息 —— 忘了把解析结果存入
c.Set() - OPTIONS 预检失败或跨域 header 缺失 —— 中间件注册顺序错,没放在
middleware.CORS()之后
实操建议:
- 用
c.Request().Header.Get("Authorization")获取原始头 - 用
strings.CutPrefix()或strings.SplitN(authHeader, " ", 2)安全提取 token,避免IndexOutOfRange - 校验失败时统一返回
c.JSON(http.StatusUnauthorized, echo.Map{"error": "invalid token"}),不要用http.Error - 校验成功后调用
c.Set("user_id", userID),方便下游 handler 使用c.Get("user_id")
JWT解析必须显式调用库,不能只比对字符串
如果你用的是 JWT,validToken == "xxx" 这种硬编码或白名单方式只适合开发调试。生产环境必须解析 signature、检查 exp、验证 issuer 等字段,否则 token 一旦泄露就永久有效。
推荐组合:
- 用
github.com/golang-jwt/jwt/v5(注意 v5 是当前稳定版) - 密钥从环境变量或配置中心加载,不要硬编码在代码里
- 解析失败时区分错误类型:
jwt.ErrTokenExpired返回 401,jwt.ErrSignatureInvalid也返回 401,但日志要记录异常细节 - 避免在中间件里做耗时操作(如查 DB),可先验签,再在业务 handler 中按需查用户信息
示例片段(非完整):
Echo框架 5.1.0 版本源码包下载,适合关注 RealIP 行为变化、StartConfig.Listener、NewDefaultFS 和观测性中间件入口的开发团队。
func jwtAuthMiddleware(secretKey string) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
auth := c.Request().Header.Get("Authorization")
if auth == "" {
return c.JSON(http.StatusUnauthorized, echo.Map{"error": "missing Authorization header"})
}
tokenStr := strings.TrimPrefix(auth, "Bearer ")
if tokenStr == auth { // 未匹配到 Bearer 前缀
return c.JSON(http.StatusUnauthorized, echo.Map{"error": "invalid auth format"})
}
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(secretKey), nil
})
if err != nil || !token.Valid {
return c.JSON(http.StatusUnauthorized, echo.Map{"error": "invalid or expired token"})
}
if claims, ok := token.Claims.(jwt.MapClaims); ok {
c.Set("user_id", claims["sub"])
c.Set("exp", claims["exp"])
}
return next(c)
}
}
}
中间件注册顺序直接影响认证是否生效
Echo 的中间件是链式执行的,顺序错了会导致 CORS 预检跳过认证、日志漏打、甚至 panic 恢复失效。
正确顺序应为(从外到内):
-
middleware.Recover()—— 最外层兜底 -
middleware.Logger()—— 记录原始请求,含未认证状态 -
middleware.CORS()—— 必须在认证前,否则 OPTIONS 请求不会被放行 - 你的
jwtAuthMiddleware()—— 放在 CORS 之后、路由之前 - 路由 handler
错误写法示例(会导致预检失败):
e.Use(jwtAuthMiddleware(secret)) e.Use(middleware.CORS()) // ❌ 错:CORS 在认证之后,OPTIONS 请求进不来
测试时容易忽略的边界情况
本地 curl 测试通过不代表线上安全。真实请求中常出现这些情况:
- Header 大小写混用:
authorization、AUTHORIZATION、Authorization——c.Request().Header.Get()是大小写不敏感的,没问题 - 空格或换行符混入 token:
"Bearer \n xyz"—— 用strings.TrimSpace()清理后再解析 - 多个 Authorization 头 —— Go net/http 默认只取第一个,无需额外处理
- token 中含 URL 不安全字符(如
+、/)—— JWT base64url 编码已处理,不用解码
最易被忽略的一点:中间件里没处理 context.Context 超时或取消,导致恶意长 token 持续占用 goroutine。建议在解析前加 ctx, cancel := context.WithTimeout(c.Request().Context(), 5*time.Second),并在 defer 中 cancel()。

















