github.com/gofiber/jwt/v3 是 fiber v2.50+ 唯一稳定可用的 jwt 中间件,需显式运行 go get github.com/gofiber/jwt/v3 安装;v4 因返回类型不兼容 fiber.handler 而不可用,误装后应执行 go get github.com/gofiber/jwt/v3@latest 覆盖并确认 go.mod 锁定 v3.x.x。

用 github.com/gofiber/jwt/v3 是当前 Fiber v2.50+ 下唯一稳定可用的 JWT 中间件,v4 尚未适配新上下文接口,硬上会报 cannot use jwt.New() (value of type fiber.Handler) as fiber.Handler。
怎么装对版本并避免类型错误
必须显式安装 v3:运行 go get github.com/gofiber/jwt/v3。别用 go get github.com/gofiber/jwt——它默认拉 v4,而 v4 的 jwt.New() 返回类型与 Fiber v2.50+ 的 fiber.Handler 不兼容。如果你已误装 v4,先执行 go get github.com/gofiber/jwt/v3@latest 覆盖,并检查 go.mod 里是否锁定为 v3.x.x。
HS256 和 RS256 配置差异在哪
HS256 用对称密钥,直接传 SigningKey: []byte("your-secret");RS256(如 AWS Cognito)必须用非对称密钥,不能塞 jwks.json 文件内容进 SigningKey,否则报“密钥类型无效”。正确做法是解析 JWKS 并转成 map[string]interface{} 后赋给 SigningKeys 字段:
keys, _ := jwk.Fetch(context.Background(), "https://cognito-idp.{region}.amazonaws.com/{user-pool-id}/.well-known/jwks.json")
config := jwt.Config{
SigningKeys: keys,
SigningMethod: "RS256",
}
注意:SigningKeys 是 map 类型,不是 raw bytes;SigningMethod 必须显式指定,否则默认 HS256,RS256 场景下会静默失败。
中间件注册后怎么取用户信息
JWT 解析成功后,payload 存在 c.Locals["user"] 里,类型是 jwt.MapClaims 或你自定义的结构体。务必做类型断言和判空:
if user, ok := c.Locals["user"].(jwt.MapClaims); !ok { return c.Status(401).SendString("invalid user claim") }- 别用
context.WithValue(c.Context(), ...),Fiber 的ctx.Context()和ctx.Locals是两套机制,前者完全不生效 - 如果用了自定义 Claims 结构体(比如
type MyClaims struct { UserID int `json:"user_id"` }),需在jwt.New()时传Claims: &MyClaims{},否则c.Locals["user"]还是MapClaims
为什么 /login 总被 401 拦住
因为 app.Use(jwt.New(...)) 是全局注册,所有路由(包括 /login)都会走校验。必须绕过登录路由:
- 用分组方式:创建
auth := app.Group(""),然后auth.Use(jwt.New(...)),再把需要保护的路由挂到auth下;/login直接挂app上 - 或手动跳过:在中间件里检查路径
if c.Path() == "/login" { return c.Next() },但不推荐——耦合重、易漏 - 更关键的是:确保
StrictRouting: true已启用,否则像/login/和/login可能被当作不同路由,其中一个没被绕过
最常被忽略的一点:JWT 中间件只管 token 本身有效性(签名、过期、格式),不查用户是否被禁用、角色是否变更。权限校验必须另写中间件,且必须基于 c.Locals["user"] 提取的 ID 去 DB 或缓存查实时状态,不能只比对 payload 里的 role 字段。











