新闻详情

新闻详情

首页 / 资讯中心 / 详情

​编辑 JWT 退出登录之后还能用?四种让它失效的办法,附可运行的 Python 演

发布时间:2026/9/30 8:16:59来源:尧图网络
​编辑 JWT 退出登录之后还能用?四种让它失效的办法,附可运行的 Python 演
前两天帮朋友看一个后台系统他问了个问题用户点了「退出登录」前端把 token 删了但如果这个 token 之前已经被人抓包拿走拿着它还能调接口吗答案是能一直能用到它过期为止。这是 JWT 最常被问到、也最容易被忽略的一件事JWT 本身是无状态的服务端验的只是签名和过期时间它不知道「这个用户已经退出了」。这篇用一个不依赖任何第三方库的 Python 脚本把这件事和四种常见的处理办法都跑一遍最后说各自的代价。先复现问题为了不依赖 PyJWT这里手写一个最小的 HS256 签发和校验只用于演示生产环境请用成熟的库import base64, hashlib, hmac, json, time, uuid SECRET bdemo-secret-only-for-this-post def b64(b): return base64.urlsafe_b64encode(b).rstrip(b).decode() def unb64(s): return base64.urlsafe_b64decode(s * (-len(s) % 4)) def sign(payload): head b64(json.dumps({alg: HS256, typ: JWT}).encode()) body b64(json.dumps(payload).encode()) sig hmac.new(SECRET, f{head}.{body}.encode(), hashlib.sha256).digest() return f{head}.{body}.{b64(sig)} def verify(token): head, body, sig token.split(.) expect hmac.new(SECRET, f{head}.{body}.encode(), hashlib.sha256).digest() if not hmac.compare_digest(expect, unb64(sig)): raise ValueError(bad signature) p json.loads(unb64(body)) if p[exp] time.time(): raise ValueError(expired) return p def login(uid, ttl3600, **extra): now int(time.time()) return sign({sub: uid, iat: now, exp: now ttl, jti: uuid.uuid4().hex, **extra})然后模拟「退出登录」t login(u1) print([0] 退出前:, verify(t)[sub]) # 用户点了退出登录前端删掉 token……但如果 token 已经被别人拿到 print([0] 退出后同一个 token:, verify(t)[sub], - 依然有效)输出[0] 退出前: u1 [0] 退出后同一个 token: u1 - 依然有效这就是问题本身。下面四种办法本质上都是在「无状态」里加回一点状态。办法一jti 黑名单每个 token 带一个唯一的jti。退出登录时把它记进黑名单校验时多查一步。blacklist {} # jti - exp真实项目放 RedisTTL exp - now def logout_blacklist(token): p verify(token) blacklist[p[jti]] p[exp] def verify_bl(token): p verify(token) if p[jti] in blacklist: raise ValueError(revoked) return p[1] 黑名单后: revoked关键细节是黑名单的过期时间设成 token 剩余的有效期。token 本来就会过期过期之后黑名单里那条记录也就没用了Redis 的 TTL 正好自动清理黑名单不会无限膨胀。代价每个请求多一次 Redis 查询。本地用 dict 测不出差别我测了一下纯验签和验签加查 dict 都在 4~5 微秒这个对比没有意义真实开销是那一次网络往返。办法二用户级 token 版本号黑名单只能踢掉「这一个」token。如果场景是「改了密码所有设备都要重新登录」就需要版本号token_ver {u1: 1} # 真实项目存用户表或 Redis def login_v(uid): return login(uid, vertoken_ver[uid]) def verify_v(token): p verify(token) if p[ver] ! token_ver[p[sub]]: raise ValueError(version mismatch) return p phone, laptop login_v(u1), login_v(u1) token_ver[u1] 1 # 改密码 / 退出所有设备[2] phone: version mismatch [2] laptop: version mismatch [2] 新登录: u1一次1这个用户之前签发的所有 token 同时失效。存储量是「每用户一个整数」比黑名单省得多。缺点是粒度粗没法只踢掉某一台设备。想要设备粒度就得把版本号细化到「用户 设备」其实就慢慢变回 session 了。办法三短 access 可撤销的 refresh这是目前最常见的组合access token 很短几分钟到十几分钟不做任何撤销检查refresh token 存在服务端可以删。refresh_store {} # refresh_id - uid真实项目存库/Redis def login_pair(uid): rid uuid.uuid4().hex refresh_store[rid] uid return login(uid, ttl2), rid # access 只活 2 秒方便演示 def refresh(rid): uid refresh_store.pop(rid, None) # 用一次就作废轮换 if uid is None: raise ValueError(refresh revoked or reused) return login_pair(uid) access, rid login_pair(u1) refresh_store.pop(rid) # 退出登录删掉 refresh[3] 退出后 access 仍可用: u1 [3] 2 秒后 access: expired [3] 拿旧 refresh 换新: refresh revoked or reused注意第一行退出之后access token 在它剩余的有效期内依然能用。这个方案不是「立即失效」而是「最多再活 N 分钟」。对大部分业务这个窗口是可以接受的对金融、后台管理这种场景可能不行要叠加办法一。refresh里那个「用一次就作废」叫轮换rotation。它顺带能发现 refresh token 被盗如果合法用户和攻击者先后拿同一个 refresh 来换后到的那个一定失败这时候可以直接把这个用户的所有 refresh 都吊销掉。办法四别用 JWT 做会话说句可能不讨喜的如果你的系统是单体应用、有 Redis、需要「退出立即失效」「踢人」「看在线设备列表」那服务端 session 随机 session id 就是更合适的方案。上面三种办法加到最后你会发现自己在 JWT 外面又实现了一遍 session。JWT 真正省事的场景是多个服务之间传递身份、服务方不方便访问同一个存储、或者 token 的有效期本来就很短。怎么选需求建议退出后「最多再有效几分钟」可以接受办法三短 access 可撤销 refresh退出必须立即失效办法三 办法一只在退出时写黑名单改密码后所有设备下线办法二或者吊销该用户全部 refresh需要在线设备列表、单设备踢出老老实实用 session局限说在前面文中的签发和校验是为了演示手写的没有处理alg字段校验、nbf、时钟偏差这些生产环境请用成熟的库并且显式指定允许的算法。性能那一段只是本机粗测真实开销要看你的 Redis 部署。我调试 token 的时候习惯把它贴进 forxi.cn 的 JWT 解析工具里看一眼 payload在浏览器本地解析exp、jti、ver这些字段对不对一眼就能看出来比自己 base64 解码快。不过要提醒一句线上用户的真实 token 别往任何在线工具里贴包括我这个。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

油气领域多智能体协同与领域大模型落地实践 2026/9/30 9:18:58

油气领域多智能体协同与领域大模型落地实践

1. 项目概述:油气行业正迎来一场静默却深刻的“智能体革命”最近在几个能源行业技术沙龙里,我反复听到一个词被拎出来讨论——不是“数字孪生”,也不是“工业互联网”,而是“多智能体协同”。这个词乍一听像科幻小说里的设定&…

阅读更多 →
大模型服务器部署实战:显存估算、推理框架选型与生产级流程 2026/9/30 9:18:58

大模型服务器部署实战:显存估算、推理框架选型与生产级流程

这两年我帮团队和外部客户落地了十多个大模型推理服务,从最初几个人围着一台 4090 折腾,到后来用多卡 GPU 机器扛线上流量,框架选型、云服务配额、部署流程这些事基本都踩过一遍。到了 2026 年,大模型服务器部署其实已经有一套成熟…

阅读更多 →
金融客服合规引擎:实时情绪识别与敏感词拦截实战 2026/9/30 9:18:58

金融客服合规引擎:实时情绪识别与敏感词拦截实战

简介:这份资料面向金融科技从业者、客服系统产品经理及大模型应用开发者,聚焦金融客服场景下质效提升与合规管控的双重难题,给出基于DeepSeek的完整技术方案。内容围绕对话情绪识别与敏感词实时拦截两条主线展开,涵盖语料特征提取…

阅读更多 →
动态规划、多目标优化与启发式算法:工程调度问题求解实战 2026/9/30 9:18:58

动态规划、多目标优化与启发式算法:工程调度问题求解实战

复杂场景下的规划问题,我做了这么多年,最大的感受就是它从来不是"一个目标、一个约束、一个最优解"的教科书题目。无论是物流车辆调度、生产线排程、芯片布图,还是电力系统的机组组合规划,实际碰到的需求几乎全是多目标…

阅读更多 →
规划问题三板斧:动态规划、多目标优化与启发式算法实战解析 2026/9/30 9:18:58

规划问题三板斧:动态规划、多目标优化与启发式算法实战解析

“3.45”这个编号,看着像是某份讲义或者课程大纲里的一个小节号,但它背后站着的,其实是计算机科学里三座绕不开的山头:多目标优化、动态规划、启发式算法。这几年不管是面算法岗,还是自己做实际项目,我越来…

阅读更多 →
TensorFlow核心原理与生产级部署实战指南 2026/9/30 9:18:48

TensorFlow核心原理与生产级部署实战指南

1. 这不是“装个库”那么简单:TensorFlow到底在解决什么问题?你搜“tensorflow安装”,页面跳出一堆报错截图——CUDA版本不匹配、pip install卡死、import失败红字满屏。但真正卡住你的,从来不是那行命令本身。我带过三十多个从零…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉