JWT和每个用户一个(!)会话/没有并发会话

问题描述 投票:5回答:5

我们当前的应用程序使用HTTP会话,我们想用JWT替换它。

该设置仅允许每个用户使用一个会话。这意味着:

  1. 用户在设备1处登录 用户登录设备1(创建新会话)
  2. 用户在设备2处登录 用户登录设备2(创建新会话) 用户未登录设备1(会话被破坏)

这是有效的,因为会话ID和用户ID之间存在服务器端关系。


使用JWT,我可以想象在用户数据库中有一些计数器,每次登录都会增加,即:

  1. 用户在设备1处登录 JWT令牌签名包含计数器+ 1(并保存新的数据库计数器)
  2. 用户在设备2处登录 JWT的签名包含计数器+ 1,它会增加并保存到db。

现在有了每个请求,我必须检查传入的签名对于当前计数器值是否正确。

这在某种程度上使它成为有状态的。 :(

但是...... JWT的一个好处是,无需访问任何数据库或会话存储来验证令牌。


是否有其他一些防止并发登录的解决方案?也许某些东西在没有数据库访问的情况下工作并保持无状态

session single-sign-on single-page-application jwt
5个回答
5
投票

你非常接近解决方案。

为此,您需要以下内容: 1.在令牌中包含iat(发出令牌的时间) 2.某处存储用户上次登录的时间,例如在用户的个人资料中。

现在,在验证令牌时,请进行额外检查:iat(Issued At)必须等于或晚于上次登录时间。这隐含地使较旧的令牌无效。


1
投票

如何在任何其他设备上关闭用户的会话。

关于什么。每次用户登录时,您按设备类型保存上次登录,并向所有相同类型的设备发送推送通知(假设为一个)?

在这种情况下,在浏览器上,您可以将推送通知发送到浏览器,只需检查当前该浏览器何时关闭会发生什么?

对于移动应用,您可以通过关闭指令向移动应用发送推送通知


0
投票

这是一种不同的解决方案,在某些情况下可能更贴合。

您仍然需要转到数据库,但假设您的大多数用户只有一台设备且只有一些设备有第二台设备,您可以使用以下策略:

在登录期间(新令牌请求)让客户端提供设备ID。将其与用户的“last_device”值进行比较。如果不同则表示用户已更改为新设备。

发生这种情况时,请在特殊表中为此用户添加epoc条目。 userid:唯一引用用户(id)不为null epoc:时间戳

这个想法是这个表可能比完整的用户表小得多。只有最近登录过多个设备的用户才能在此表中输入一个条目。所以扫描这个表是有效的。在以正常方式验证令牌之后,检查iat(Issued At)是否不在用户的会话epoc之前。如果是,则该设备不是最新登录的设备。

此解决方案还有其他用途:它允许用户远程注销自己(使用当前时间为用户创建新条目,这有效地使所有现有令牌无效)。

通过删除比任何令牌的最长生命周期更早的项目来维护此表。


0
投票

首先,当使用JWT进行会话时,定义以下内容非常重要:

  • 无状态令牌:包含令牌内的所有会话数据。这样您就不需要将它存储在任何地方。
  • Steteful Token:包含会话ID。当服务器收到令牌时,他将需要检索有关会话的信息。

如果您使用有状态解决方案来使令牌无效,您可以在数据库中查询该用户的最后一个会话ID,并与收到的令牌进行比较。 在无状态解决方案中,正如其他答案所指出的那样,您可能需要在某个地方保持状态。但是与状态令牌相比,你只需要像你建议的那样存储一个计数器,或者像Tahaan所建议的那样存储“last_login”。

如果您觉得使用数据库太重,我建议使用像Redis这样的内存解决方案,除了速度非常快之外,它还能够轻松设置持久数据的持续时间。这样,如果出现以下情况,用户必须再次登录:

  • 用户登录其他设备。
  • 过了一段时间。

0
投票

我怎么认为可以做到。只需创建一个随机id(让我们调用此验证代码),并在生成jwt时将其存储在DB中。在JWT中编码。每当使用jwt进行任何请求时,检查jwt中编码的验证代码是否与DB匹配。如果用户尝试登录其他设备,它将重新生成验证代码,使所有其他会话到期。

© www.soinside.com 2019 - 2024. All rights reserved.