signingkey用于对称算法(如hs256),signingkeys用于非对称算法(如rs256);aws cognito必须用signingkeys并正确解析jwks为kid映射的map,同时显式设置signingmethod="rs256"。

直接用 jwtware.New() 配置 JWT 认证,但多数人卡在 SigningKey 类型错、密钥加载方式不对、或中间件挂载位置导致 401 不生效——根本原因不是 JWT 本身复杂,而是 Fiber 的 jwtware 中间件对密钥格式和执行链路有强约束。
SigningKey 和 SigningKeys 到底该用哪个?
看签名算法决定:
- HS256 / HS384 / HS512:必须用
SigningKey []byte,传入原始 secret 字符串的字节切片(如[]byte("my-secret")) - RS256 / ES256 等非对称算法(比如 AWS Cognito):必须用
SigningKeys map[string]interface{},且内容得是解析后的 JWKS JSON,不能直接传 raw bytes
常见错误:SigningKey: signingKey 传了 jwks.json 文件内容,结果报 “密钥类型无效”——因为 SigningKey 期待的是对称密钥字节,不是 JWKS 结构体。
如何正确加载 AWS Cognito 的 JWKS 密钥?
不能直接 json.Unmarshal 到 map[string]interface{} 就完事。Cognito 的 JWKS 是一个包含 keys 数组的 JSON,而 jwtware.Config.SigningKeys 要求的是以 kid 为 key 的 map,形如 map[string]interface{}{"kid-abc123": {...}}。
实操建议:
- 先读取
jwks.json,用json.Unmarshal解析为struct { Keys []JWK }(JWK含Kid,Kty,N,E等字段) - 遍历
Keys,对每个 key 构建map[string]interface{}并按Kid存入最终 map - 传给
SigningKeys,同时显式设置SigningMethod: "RS256"
漏掉 SigningMethod 或 kid 匹配失败,就会报 “意外的 jwt 密钥 id=XXXXX”。
中间件挂载位置影响认证是否触发
jwtware 不是全局过滤器,它只对注册路径下的请求生效。错误写法:app.Use(jwtware.New(...)) —— 这会让所有请求(包括 /health、/favicon.ico)都走 JWT 校验,必然 401。
推荐做法:
- 按业务分组挂载,例如
api := app.Group("/api", jwtware.New(...)) - 敏感路由再叠加其他中间件,如
api.Get("/admin", ipWhitelist, handler) - 确保前端请求的
Authorization: Bearer xxxheader 真的发到了该路径下,别因前端路由配置或代理规则被截断
调试时加一行 c.Locals("user", token.Claims),然后在后续 handler 里检查 c.Locals("user") 是否存在,比盲猜更可靠。
为什么校验通过后 ctx.UserContext() 拿不到用户信息?
jwtware 默认把解析后的 *jwt.Token 存在 c.Locals("user"),不是 ctx.UserContext()。Fiber 的上下文是独立实例,UserContext() 是 Go 原生 context.Context,JWT 中间件不往里面塞东西。
正确取法:
-
user := c.Locals("user")→ 得到*jwt.Token -
claims := user.Claims.(jwt.MapClaims)→ 转成 map 获取claims["sub"]、claims["email"]等 - 若用自定义 claims struct,需在
jwt.ParseWithClaims阶段指定,jwtware不自动支持
最容易被忽略的一点:Cognito 的 sub 是用户唯一 ID,不是用户名;cognito:username 才是登录名——字段名得查你自己的 JWKS payload,不能默认套用。











