Fiber本身不内置JWT认证逻辑,fiber.JWT中间件仅解析token,默认存*jwt.Token到c.Locals("user"),不自动解claims,登录、登出、黑名单、Cookie安全等均需手动实现。

直接上结论:Fiber 本身不内置 JWT 认证逻辑,fiber.JWT 中间件只是个解析器,它默认只存 *jwt.Token 到 c.Locals("user"),不自动解出 claims,也不处理登录、登出、黑名单或 Cookie 安全设置——这些都得你手写补全。
为什么 c.Locals("user") 拿不到用户 ID
常见现象是调用 c.Locals("user") 返回 nil 或类型断言失败。根本原因不是 Token 验证失败,而是中间件压根没把 claims 解出来塞进去。
-
fiber.JWT默认的ParseTokenFunc是空的,所以c.Locals("user")里只有原始*jwt.Token实例,不是map[string]interface{} - 必须显式配置
Config.ParseTokenFunc,且函数签名要匹配github.com/golang-jwt/jwt/v5:接收*jwt.Token,返回interface{}和error - 推荐用
token.Claims.(jwt.MapClaims)断言,别用结构体指针初始化MapClaims,容易字段丢失 - 确保路由已挂载该中间件,且请求带了合法的
Authorization: Bearer xxx头
ParseTokenFunc 怎么写才不出错
这个函数决定你后续能拿到什么数据。写错会导致 claims 为空、字段类型 panic 或数字精度丢失。
- JWT 标准里数字类字段(如
exp、user_id)在 JSON 中是 number,Go 的json.Unmarshal默认转成float64,所以MapClaims里的user_id是float64类型,不是int64 - 避免精度丢失:用户 ID 强烈建议存字符串,比如
"user_id": strconv.FormatUint(user.ID, 10) - 别在
ParseTokenFunc里做数据库查询或耗时操作,它在每次请求都执行 - 示例写法:
config := jwt.Config{ SigningKey: jwt.SigningKey{Key: []byte("secret")}, ParseTokenFunc: func(token *jwt.Token) (interface{}, error) { claims, ok := token.Claims.(jwt.MapClaims) if !ok { return nil, fmt.Errorf("invalid claims type") } return claims, nil // 这样 c.Locals("user") 才是 map[string]interface{} }, } app.Use(jwt.New(config))Cookie 存 Token 有哪些硬性安全要求
如果用 Cookie 传 Token(而非 Authorization header),漏掉任一配置都可能被 XSS 或 CSRF 利用。
-
HttpOnly: true—— 防止 JS 读取,阻断 XSS 盗 Token -
Secure: true—— 仅 HTTPS 传输,本地开发可临时关,但上线必须开 -
SameSite: http.SameSiteStrictMode或http.SameSiteLaxMode—— 防 CSRF -
Expires必须 ≤exp字段值 —— 否则浏览器 Cookie 过期时间比 Token 本身还晚,服务端已拒收,客户端还在发 - 登出时不能只删 Cookie,必须配合服务端黑名单(比如 Redis 存失效 Token),否则 Cookie 被盗后仍有效
BasicAuth 和 JWT 能混用吗
能,但别在同一个中间件链里乱套。它们解决的是不同层级的问题:BasicAuth 是传输层凭据校验(HTTP header),JWT 是应用层身份声明验证(token payload)。
- BasicAuth 中间件只负责解
Authorization: Basic xxx并给你 username/password 字符串,它不生成 Token,也不验证 Token - 如果你要用 BasicAuth 做登录入口,再签发 JWT,那得在 BasicAuth 成功后的 handler 里手动调
jwt.NewWithClaims生成 Token - 千万别把
fiber.BasicAuth()和fiber.JWT()都app.Use()全局挂载——前者会拦住所有请求(包括 OPTIONS),后者又需要 Bearer 头,结果就是预检失败、CORS 报错 - 正确做法:用
app.Group("/api", fiber.BasicAuth(...))保护登录路由,其他业务路由用fiber.JWT保护
最常被忽略的一点:JWT 的「无状态」是假象。真正无状态的是验证过程,但登出、权限变更、密钥轮换这些事,全得靠服务端有状态配合。别以为签发完 Token 就万事大吉了。
-

















