fiber.JWT中间件默认不解析claims,需配置ParseTokenFunc手动解析并校验alg、exp等,且须返回与handler一致的claims类型;依赖用户身份的中间件必须挂载在JWT之后。

fiber.JWT中间件默认不解析claims,直接断言会panic
你写 c.Locals("user").(*jwt.Token) 能取到对象,但它的 Claims 字段还是未解析的原始结构;若强行转成 jwt.MapClaims 或自定义 claims 结构体,必定 panic。根本原因不是 token 无效,而是 Fiber 的 fiber.JWT 中间件默认只存原始 *jwt.Token,不做任何 claims 解析。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 必须配置
ParseTokenFunc字段,且返回值类型要和后续 handler 中使用的类型一致(如jwt.MapClaims或自定义MyClaims) -
ParseTokenFunc签名必须是func(*jwt.Token) (interface{}, error),不能返回[]byte或直接nil - 别在 handler 里重复调用
jwt.ParseWithClaims——中间件已做过一次完整校验,重复解析浪费 CPU 且可能因时钟漂移导致误判
ParseTokenFunc必须显式校验alg和exp,否则JWT可被绕过
很多 Fiber 示例代码里把 ParseTokenFunc 写成简单返回 jwt.MapClaims{},再靠中间件内部逻辑兜底,这是错的。v5 版本的 github.com/golang-jwt/jwt/v5 不再自动校验 exp、iss 或算法白名单,全靠你手动控制。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 在
ParseTokenFunc内部调用token.Claims.Validate(),它会统一检查exp、iat、nbf等标准声明 - 先判断
token.Method.Alg()是否在允许列表中(如"HS256"),拒绝alg: none攻击 - 密钥必须从环境变量读取,长度 ≥32 字节:
[]byte(os.Getenv("JWT_SECRET")),别硬编码"secret" - 若使用 RS256,
ParseTokenFunc应返回*rsa.PublicKey,且需提前加载 PEM 文件
Gin 和 Fiber 的鉴权中间件顺序不能互换
Fiber 没有“中间件注册顺序决定执行顺序”的显式约束,但它依赖 c.Locals 的写入时机。如果你把权限校验逻辑写在另一个中间件里,并期望从 c.Locals("user") 读用户 ID,那这个中间件**必须挂载在 fiber.JWT 之后**,否则 c.Locals("user") 是 nil。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 所有依赖用户身份的中间件(如 RBAC、日志注入、审计)都应放在
app.Use(jwtMiddleware)后面 - 健康检查、静态资源、CORS 等无需鉴权的路由,应在挂载 JWT 中间件前注册,避免无谓解析
- 不要用字符串字面量当 context key:
type userKey string; const userIDKey userKey = "user_id",否则跨包传参时类型不匹配
微服务间调用不能复用前端 JWT,Fiber 也要区分入口来源
前端发来的 Authorization: Bearer xxx 和网关透传的 X-Service-Token: yyy 是两类凭证:前者面向用户、有效期长、含敏感字段;后者面向服务、时效短(建议 ≤5 分钟)、aud 必须精确匹配当前服务名。Fiber 默认只认 Authorization 头,不处理其他 header。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 为服务间调用单独写一个中间件,从
r.Header.Get("X-Service-Token")提取并解析,与主 JWT 中间件隔离 - 两个中间件都应校验
claims.Audience:用户 token 校验是否包含"web",服务 token 校验是否等于当前服务名(如"user-service") - 服务 token 必须用 RS256 签发,公钥启动时加载,私钥绝不落地到业务服务
- 别把原始 token 存进
context.WithValue——调试日志或 panic 堆栈可能意外泄露它
fiber.JWT 设计上就假设你只做“身份认证”,不负责权限决策;而真实项目里,权限往往依赖 claims 中的 perms 字段或角色映射,这些必须在 ParseTokenFunc 里完成解析并注入 locals,而不是留到 handler 里再查 DB 或 Redis。

















