必须手动添加Redis黑名单中间件,因echo-jwt/v4仅校验签名与时间;需在它之后链式注册,从c.Get("user")取token、提取jti、用revoked:{jti}键查Redis是否存在。

echo-jwt/v4 之后必须加自定义中间件查 Redis
echo-jwt/v4 默认只做签名和时间校验,token.Valid 方法完全不碰 Redis 或 DB。它把解析好的 *jwt.Token 放进 c.Get("user"),但黑名单检查得你手动补——不是改它的配置,而是在它之后链式注册一个新中间件。
常见错误现象:echo-jwt 验证通过了,但用户刚登出,请求仍被放行;或者中间件里重复调用 ParseWithClaims 导致 panic。
- 确保
echo-jwt中间件已注册,且顺序在黑名单中间件之前 - 黑名单中间件中直接从 context 取值:
token, ok := c.Get("user").(*jwt.Token),别再自己 parse - 提取
jti字段:jti, ok := token.Claims.(jwt.MapClaims)["jti"].(string);若没设jti,fallback 到token.Raw(但不推荐,体积大、易冲突) - Redis key 命名统一用
revoked:{jti},TTL 设为与 token 剩余有效期一致(不是固定值)
Redis 存什么、存多久,直接影响黑名单有效性
存错字段或 TTL 不对,会导致漏检或内存爆炸。Redis 不是“存 token 字符串”,而是存一个轻量 key-value:key 是 revoked:{jti},value 可为空字符串,靠 TTL 自动清理。
性能影响很直接:每次鉴权多一次 Redis GET,必须用 pipeline 或连接池压测;兼容性上,go-redis/v9 的 Exists 返回 int64,别拿它和 true 直接比。
- TTL 必须动态计算:用
token.Claims.(jwt.MapClaims)["exp"]减去当前时间戳(秒级),结果 ≤ 0 就跳过写入 - 写入时用
SET revoked:{jti} "" EX {ttl} NX(NX防重复,EX确保自动过期) - 查的时候用
Exists,不是Get——我们只关心 key 是否存在,不读 value - 如果用的是
redis.Client(v9),调用client.Exists(ctx, key).Val(),返回 1 表示在黑名单
KeyFunc 里不拦 alg: none 和时间漂移,黑名单形同虚设
即使 Redis 黑名单逻辑写对了,如果 echo-jwt.Config.KeyFunc 没做基础防护,攻击者能绕过签名验证,直接伪造任意 jti,让黑名单查询失效。
典型错误:KeyFunc 只返回密钥,不校验 token.Header["alg"];或没传 jwt.WithValidTimeFunc,导致服务端时间快几秒就误判 token 过期,用户刚登录就 401。
- 在
KeyFunc中显式拒绝alg == "none":if token.Header["alg"] == "none" { return nil, errors.New("alg cannot be none") } - 启用时间容错:
echo-jwt.Config.TimeFunc = time.Now,并在VerifyExpiresAt等逻辑外加jwt.WithValidTimeFunc(func(t int64) bool { return time.Now().Add(5 * time.Second).Unix() > t }) -
exp字段必须是秒级int64,不是毫秒——Golang 的time.Now().Unix()正确,time.Now().UnixMilli()会立刻报"token is expired"
登出接口写 Redis 要防竞态,查黑名单要短路
用户点登出后立刻发一个带旧 token 的请求,可能因 Redis 写入延迟,导致黑名单还没生效就被放行。这不是概率问题,是必然发生的窗口期。
另一个坑是:黑名单中间件里没 early return,查完 Redis 还继续往下走,最后还是进了业务 handler。
- 登出接口必须用原子命令写 Redis:
SET revoked:{jti} "" EX {ttl} NX,NX保证只写一次,避免并发重复登出放大延迟 - 黑名单中间件中,一旦
Exists返回非零,立刻return echo.NewHTTPError(http.StatusUnauthorized, "token revoked"),不走后续逻辑 - 不要在中间件里做重试或 fallback——查不到就是有效,查到了就必须拒,逻辑必须干净
- 注意时钟漂移:如果服务集群节点时间不一致,建议所有机器同步 NTP,或统一用 Redis 服务器时间(
TIME命令)校准 TTL 计算
Redis 黑名单本质是用空间换可控性,但它不解决 jti 生成碰撞、客户端不清理 token、或网络重放等问题。真正安全的退出,得把 jti 生成、登出写入、鉴权拦截、时钟对齐这四步全串起来,少一环,就等于没关严门。


















