正确做法是避免全局注册JWT中间件,改用独立路由组:public := e.Group("/api")放免鉴权接口,auth := e.Group("/api/v1")加auth.Use(jwt.Middleware(...));若必须共用路径,则需自定义中间件判断请求方法或标记跳过。

怎么让 /api 下部分接口跳过 JWT 校验
直接答案:别在 e.Use() 里注册 JWT 中间件。用 e.Group("/api") 拆出路由组,只对需要鉴权的子组注册中间件。
常见错误是把 jwt.Middleware 加到 e.Use() 全局链里,结果所有路由(包括 /api/health)都强制校验,连 OPTIONS 预检都 401。这不是“跳过”的问题,是注册方式错了。
- ✅ 正确做法:建两个独立 group,比如
public := e.Group("/api")放免鉴权接口,auth := e.Group("/api/v1")加auth.Use(jwt.Middleware(...)) - ⚠️ 路径前缀必须不同,否则无法物理隔离;若硬要共用
/api/products,就得自己写中间件判断c.Request().Method == "GET"后提前return nil - ❌ 别在中间件里写
if c.Path() == "/api/login"白名单——路径带参数(如/users/:id)或大小写变化时就失效,且漏掉预检请求
JWT 中间件注册顺序影响角色校验吗
影响非常大。RBAC 中间件读不到用户信息,90% 是因为顺序错了或者 ContextKey 对不上。
echojwt.New() 必须先执行,把解析后的 Claims 写进 c.Get("user");之后的 RBAC 中间件才能读取并校验角色。如果反过来,或者 RBAC 放在全局 e.Use() 最前面,c.Get("user") 就是 nil,直接 panic。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 注册顺序必须是:
e.Use(logger)→e.Use(echojwt.WithConfig(cfg))→e.Use(rbacMiddleware) -
cfg.ContextKey必须显式设为"user",不能依赖默认值;RBAC 里也必须用c.Get("user"),不是"claims"或"auth_user" - RBACK 中间件开头要加
if user == nil { return c.NoContent(401) },别假设 JWT 一定成功
为什么解析 JWT 时类型断言会 panic
因为没传对 Claims 类型,或忽略 jwt.ParseWithClaims() 的 err。
用 github.com/golang-jwt/jwt/v5 时,ParseWithClaims(authStr, &MyClaims{}, keyFunc) 的第二个参数必须是具体结构体指针,不能是 jwt.MapClaims。否则字段取不到,claims.UserID 是零值,断言 c.Get("user").(MyClaims) 也会失败。
- 自定义 Claims 必须嵌入
jwt.RegisteredClaims,否则过期、签发时间等校验无效 - 中间件里必须检查
err != nil,然后调用c.AbortWithStatusJSON(401, ...),不能只return c.JSON()就继续next(c) - 提取 token 优先从
c.Request().Header.Get("Authorization")取,切分后strings.TrimSpace()去空格,避免签名比对失败
OPTIONS 预检请求为啥总被 JWT 拦截
因为中间件没区分 HTTP 方法,也没提前处理预检。
浏览器发 CORS 预检时只带 Origin 和 Access-Control-Request-Method,不带 Authorization 头。JWT 中间件照常执行,ExtractToken 返回空或 err,直接 401 —— 这不是 bug,是你没告诉它“OPTIONS 不用验”。
- 最稳妥:在 JWT 中间件最开头加
if c.Request().Method == "OPTIONS" { return next(c) } - 次选:用
c.Set("skip_jwt", true)在更前置的中间件里标记,再封装一层 JWT 中间件去读这个标记 - 别指望前端加 header 解决——预检是浏览器自动发的,你控制不了它的头内容
exp 是毫秒还是秒。ESP-IDF 或某些嵌入式后端用 esp_timer_get_time() 输出毫秒级时间戳,但标准 JWT 库默认按秒解析。错一位,token 永远过期。


















