Spring Cloud Gateway过滤器如何高效拦截已封禁用户的未过期JWT?
Spring Cloud Gateway 账号封禁实时拦截解决方案
方案1:本地缓存 + 状态变更事件推送(性能最优)
- 实现逻辑:
- 用户微服务侧新增账号状态变更事件触发逻辑,用户封禁/解封操作完成后,将用户ID、最新状态推送到MQ(Kafka/RabbitMQ均可)
- 所有网关实例开启MQ广播消费模式,收到状态变更事件后更新本地Caffeine缓存,仅存储状态异常的用户ID即可,正常状态用户无需存入缓存节省空间
- 网关JWT校验过滤器中,解析出用户ID后仅需查询本地缓存,存在记录则直接返回
UNAUTHORIZED,无记录直接放行
- 性能表现:本地缓存查询为纳秒级,无任何远程调用开销,仅在用户状态变更时产生极少量MQ消息开销,对业务接口无性能影响
- 代码示例(本地缓存配置):
import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.concurrent.TimeUnit; @Configuration public class BannedUserCacheConfig { @Bean public Cache<Long, Boolean> bannedUserCache() { return Caffeine.newBuilder() // 可根据实际封禁用户规模调整最大值 .maximumSize(10000) // 兜底过期时间,避免消息丢失导致脏数据 .expireAfterWrite(24, TimeUnit.HOURS) .build(); } }
方案2:分布式缓存 + 短周期本地缓存(一致性优先)
- 实现逻辑:
- 用Redis存储全量封禁用户ID集合,用户状态变更时同步更新Redis数据,设置7天过期时间,后台定时任务每24小时全量同步一次封禁用户列表兜底
- 网关层新增10秒周期的本地二级缓存,同一个用户的请求10秒内仅查询1次Redis,大幅降低Redis访问压力
- 过滤器中优先查本地二级缓存,未命中再查Redis,存在封禁记录则拦截
- 适用场景:网关实例数量多、不方便部署MQ广播消费的场景,数据一致性比纯本地缓存更高,Redis查询性能可达万级QPS,完全满足网关流量需求
方案3:JWT版本号机制(通用型失效方案)
- 实现逻辑:
- 生成JWT时在payload中新增
user_version字段,用户状态/权限等核心信息变更时,将对应用户的版本号+1存储到Redis/用户表 - 网关校验JWT时,对比JWT携带的版本号与缓存中存储的最新版本号,不一致则直接拦截
- 同样可叠加本地短周期缓存优化版本号查询性能
- 生成JWT时在payload中新增
- 优势:可覆盖所有需要JWT主动失效的场景,包括账号封禁、权限变更、密码修改、强制下线等,扩展性更强
兜底降级策略
如果MQ/Redis等中间件故障,网关可降级为每5分钟主动拉取一次全量封禁用户列表存储到本地,保证基础拦截能力不会失效。
内容的提问来源于stack exchange,提问作者user13548798
相关产品推荐
相关产品推荐

