长篇大论short,您必须建立一种机制来删除或使令牌无效manually 在注销时。
是否应该存储 JWT 令牌?
你应该问自己的问题是
- 我需要将 JWT 令牌存储在数据库中吗?如果是这样,为什么?
上述问题不一定能解决您的logout 问题,因为您仍然需要一种机制来invalidate 存储或不存储在database 中的令牌。
not storing 数据库中的令牌的好处之一是您不必担心deleting 他们何时(无需维护或一些清理过程)
- 他们的令牌过期
- 他们的范围发生了变化
- 用户(在
password 流的情况下,我们不涉及其他flows)角色和权限在数据库中被降级或升级,因此,jwt 内部的内容已过时
- 用户被删除
- 用户退出(想知道这是否是删除令牌的充分理由)
- 令牌被泄露(棘手的一个)
- [添加其他案例]
验证令牌的有效性?
我确定您使用的是verify 端点,其目的是验证令牌是否为valid,但不必检查上述所有情况,这意味着您必须要么
- 自定义
verify 工作流程以添加更多custom checks 或
- 在令牌被
verified 用于signature validity、expiry time 和其他一些default checks 之前,您可以运行自己的custom checks,如果您的custom checks 已通过,则继续you shall not pass!
那你有什么选择?
嗯,除了blacklisting,你还可以做如下的事情
使用内存存储
只需将JWT令牌的uniquely-identifying-metadata作为key存入redis,并给它一个与JWT令牌到期时间相同的expiry time,以便令牌到期时self-destruct。
set key {replace_with_jwt_unique_identifier} ex {jwt_expiry_timestamp}
风险:Redis 是内存存储,条目不会持久化。
使用数据库
不要使用 Redis 或不想冒险。您可以将数据库与自定义数据库表一起使用。一个单独的表,要么是
- 与 JWT 记录相关并且有一个
ON DELETE CASCADE
- 与JWT记录无关,需自行维护
发出令牌时,也会填充这个新的数据库表。
常见的剩余步骤
当 normal 请求带有 JWT 时,使用 JWT 查询 in-memory 存储或 database 表以查看是否存在记录。
对于in-memory 存储一个简单的existence 检查就绰绰有余了。
对于database table,您需要进行更多检查(即存在且未过期等),如果检查通过则让请求通过,否则you shall not pass!
当出现logout request 时,如果是in-memory,存储只需删除key 并继续(如果找到),如果是database,您可以删除JWT 记录,该记录将级联到新表。
何时进行自定义检查?
嗯,你可以的
- 首先使用自定义顶级过滤器或
- 您可以扩展
verify 端点工作流来执行这些额外检查
我使用的项目不需要在logout 上使令牌失效,所以我不必过这座桥。如果我的所有custom checks 都已通过,我确实必须扩展verify 端点以确保令牌有效。
额外阅读材料
除了您指出的教程。还有一些其他的 SO 问题也讨论了类似的问题。见
What if JWT is stolen?
How to destroy JWT on logout?
More how to delete a JWT token?
How to invlidate JWT when password changed
Github issue - how to invalidate JWT
Finally the best for the last - Invalidating JWT Web Tokens