不使用黑名单的 JWT 注销功能?

JWT logout feature without using blacklist?

我以前用过JWT,但他们API不需要注销功能。

我需要为 android 应用程序的 APISPA 实施注销功能。当我查找它时,我发现有两种方法可以做到这一点。

  1. 最简单的方法是从客户端删除 JWT Token 并收工。

这背后的逻辑是,由于服务器中没有维护任何类型的会话,删除客户端中的令牌应该就足够了。 但这仍然存在这样的可能性,即如果代币落入坏人之手,即使用户不再使用该代币,他们仍然可以使用它。

如果应用程序设计良好并使用 HTTPS,那么发生这种情况的可能性非常低,并且可以通过保持令牌的有效时间短来最大限度地减少。但就我而言,令牌有效期为 30 天。

  1. 第二种选择是在服务器端维护一个令牌黑名单

这解决了即使在用户注销并停止使用后令牌仍然可用的问题。

但它增加了需要 运行 一个 cronjob 从黑名单 table 中删除过期令牌的复杂性。否则 table 最终会变得大得离谱。

它也有点破坏了使用 JWT 的意义。维护黑名单与维护会话非常相似。我们必须为每个请求 运行 一个额外的数据库查询。而且它的扩展性很差,因为没有。用户增长没有。需要列入黑名单的代币数量也会增加(对于像我这样的 API 拥有多个前端应用程序且代币有效期较长的 API,这将是一个更大的问题。

然后我想到了第三种方式。

在存储随机生成的字符串的用户 table 中添加 jwt_secret 行。使用它来签署 JWT Token 然后在每个请求中使用 jwt payload 中的 user id 来获取用户表单 db(这不是额外的查询,无论如何我们都必须这样做)并验证使用用户 jwt_secret 的令牌签名。当用户注销时,我们更改 jwt_secret 这使得所有令牌都无用。

起初我认为这是一个很好的解决方案,只是意识到在此设置中,如果用户从一台设备或浏览器注销 he/she 会从所有设备注销。

那么还有其他选择吗?或修改上述任何一种方法来解决问题的方法。还是我想多了,应该使用上述选项之一?

对于注销,正如您指出的那样,这是用户发起的操作,我认为您不需要做任何额外的事情。如果用户以某种方式没有删除他的 JWT,那就这样吧。他不会获得任何额外的权限来访问他已经有权访问的内容。

但是,您的问题似乎暗示了如何知道 JWT 是否有效的问题。同样,正如您所指出的,如果 JWT 以某种方式落入坏人之手,那么可能无法避免这种情况。但是,对于每个请求,您通常会针对该 JWT 进行多种类型的验证,例如

  • 检查 JWT 的声明,例如令牌到期日期
  • 假设索赔通过,然后根据您的数据库检查该用户的 ID table 以确保该帐户处于活动状态,未被暂停等。

我的观点是,如果您需要在服务器端跟踪发生注销的情况,您可能需要将其保存到数据库中。但是,我认为您不需要这个。