必须在测试中注册JWT中间件并正确配置SigningKey,再通过req.Header.Set("Authorization", "Bearer xxx")注入合法签名Token;若仅设Header却未挂载中间件,c.Get("user")将为nil。

如何在 Echo 单元测试中注入伪造的 JWT Token
直接往 *echo.HTTPRequest 的 Header 里塞 Authorization: Bearer xxx 就行,但必须确保中间件能识别它——关键不是“怎么加”,而是“加完中间件是否真会解析”。Echo 自身不处理 JWT,你用的 jwt.FromAuthHeader 或自定义解析器必须在测试路由链中注册,否则 token 再合法也进不了 handler。
常见错误是:写了 req.Header.Set("Authorization", "Bearer ey..."),但忘了在测试用的 echo.New() 实例上挂载 JWT 中间件,结果 handler 收到的 c.Get("user") 是 nil。
- Token 必须是格式正确的 JWT(三段式,含签名),哪怕用
github.com/golang-jwt/jwt/v5本地签发一个测试用的,别手写乱字符串 - 如果用
echo-jwt,记得传入Config.SigningKey,且类型必须是[]byte;传string会导致key is of invalid type - 测试时关闭日志输出:用
e.Logger.SetOutput(io.Discard),避免干扰断言
使用 jwt-go v5 签发测试 Token 的最小可行代码
v5 版本改了 API,jwt.NewWithClaims 返回的是指针,SignAndEncode 拆成了两步,漏掉 SigningMethodHS256 或用错 SigningKey 类型都会 panic。
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"sub": "123",
"exp": time.Now().Add(time.Hour).Unix(),
})
signedToken, err := token.SignedString([]byte("test-secret"))
if err != nil {
// 处理 err
}
req := httptest.NewRequest(http.MethodGet, "/api/me", nil)
req.Header.Set("Authorization", "Bearer "+signedToken)
注意:signedToken 是字符串,不是结构体;别误传 token(未签名对象)进去。
为什么 echo-jwt 中间件在测试里总返回 401
401 不一定代表 token 错,更可能是中间件根本没运行,或配置参数没对齐。检查三个地方:
Echo框架 5.1.0 版本源码包下载,适合关注 RealIP 行为变化、StartConfig.Listener、NewDefaultFS 和观测性中间件入口的开发团队。
-
Config.SigningKey和签发时用的 key 是否完全一致(包括空格、大小写) - 中间件是否被
e.Use()注册,而不是只在某个 group 里调用Use()却测试了根路径 - 测试请求路径是否匹配中间件生效的路由前缀(比如中间件挂载在
/api/*,但你测的是/health)
快速验证中间件是否生效:在中间件函数里加个 fmt.Println("jwt middleware hit"),看测试日志有没有输出。
绕过 JWT 验证直接设置用户上下文(仅限单元测试)
如果你只是想测 handler 逻辑,不想每次构造 token,可以用 Echo 提供的 c.Set() 强制注入用户信息。这跳过了整个 JWT 解析流程,但前提是你的 handler 只读 c.Get("user") 或类似键值,不依赖中间件的其他副作用(比如自动写 header)。
e := echo.New()
req := httptest.NewRequest(http.MethodGet, "/api/me", nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
// 手动模拟已认证用户
c.Set("user", &jwt.Token{
Claims: jwt.MapClaims{"sub": "test-user"},
})
if err := yourHandler(c); err != nil {
// 处理错误
}
这个方式快且稳定,但掩盖了真实 JWT 流程的问题——比如你 handler 里调用了 c.Get("user").(*jwt.Token),而这里塞的是 map[string]interface{},就会 panic。务必确认类型一致性。
真实环境里 token 解析失败、过期、签名不匹配的表现各不相同,单元测试里最容易忽略的是“过期时间字段 exp 必须是 int64 时间戳”,填字符串或 float64 都会让解析静默失败。










