Session JWT和每个用户一个(!)会话/无并发会话
我们当前的应用程序使用HTTP会话,我们想用JWT取代它 该设置只允许每个用户进行一次会话。这意味着:Session JWT和每个用户一个(!)会话/无并发会话,session,single-sign-on,single-page-application,jwt,Session,Single Sign On,Single Page Application,Jwt,我们当前的应用程序使用HTTP会话,我们想用JWT取代它 该设置只允许每个用户进行一次会话。这意味着: 用户在设备1上登录 用户登录到设备1(创建新会话) 用户在设备2上登录 用户在设备2上登录(创建新会话) 用户未在设备1上登录(会话被破坏) 这是因为会话id和用户id之间存在服务器端关系 使用JWT,我可以想象在用户数据库中有一些计数器,这些计数器随着每次登录而增加,即: 用户在设备1上登录 JWT令牌签名包含计数器+1(并将新计数器保存到数据库) 用户在设备2上登录 JWT
- 用户登录到设备1(创建新会话)
- 用户在设备2上登录(创建新会话)
- 用户未在设备1上登录(会话被破坏)
使用JWT,我可以想象在用户数据库中有一些计数器,这些计数器随着每次登录而增加,即:
- JWT令牌签名包含计数器+1(并将新计数器保存到数据库)
- JWT的签名包含计数器+1,它会增加并保存到db
是否有其他防止并发登录的解决方案?可能是在没有数据库访问的情况下工作并保持无状态的解决方案?您非常接近该解决方案 要做到这一点,您需要以下几点:
1.在令牌中包括iat(令牌发出的时间)
2.在某个地方存储用户上次登录的时间,例如在用户配置文件中
现在,在验证令牌时,请进行额外检查:iat(在发出)必须在或晚于上次登录时间。这意味着旧令牌无效。这是一种不同的解决方案,在某些情况下可能更适合 您仍然需要转到DB,但假设大多数用户只有一台设备,只有一些用户有第二台设备,您可以使用以下策略: 在登录期间(新令牌请求),让客户端提供设备id。将其与用户的“last_device”值进行比较。如果不同,则表示用户已更改为新设备 发生这种情况时,请在特殊表中为此用户添加epoc条目。
userid
:唯一引用用户(id)不为空epoc
:时间戳
其想法是,此表可能比完整的用户表小得多。只有最近登录了多个设备的用户才会在此表中有一个条目。因此,扫描此表是有效的。以正常方式验证令牌后,请检查iat(在下发时)不是在用户会话epoc之前。如果是,则该设备不是最近登录的设备
此解决方案还有其他用途:它允许用户自己远程注销(使用当前时间为用户创建一个新条目,这将有效地使所有现有令牌失效)
通过定期删除早于任何令牌的最大生存期的项来维护此表。首先,在会话中使用JWTs时,必须定义:
- 无状态令牌:包含令牌内的所有会话数据。此 这样你就不需要把它存放在任何地方了
- Steteful令牌:包含会话id。当服务器收到 令牌他将需要检索有关会话的信息
在无状态解决方案中,正如其他答案所指出的,您可能需要在某个地方持久化状态。但是与有状态令牌相比,您只需要存储您建议的计数器或@thetahaan建议的“last_login” 如果您觉得使用DB太重,我建议使用内存中的解决方案,例如,它除了速度非常快之外,还可以轻松设置持久化数据的持续时间。这样,如果出现以下情况,用户就必须再次登录:
- 用户在其他设备中登录
- 一段时间过去了
- 我认为这是如何做到的。
只要创建一个随机id(让我们调用此验证代码),并在生成jwt时将其存储在DB中。
用JWT对其进行编码。
无论何时使用jwt发出任何请求,都要检查jwt中编码的验证代码是否与DB中的匹配。
如果用户尝试登录到其他设备,它将重新生成验证代码,使所有其他会话过期。关闭用户在任何其他设备上的会话如何 那么,每次用户登录时,您都会按设备类型保存最后一次登录,并向所有连接的相同类型设备(假定为一个)发送推送通知 在这种情况下,在浏览器上,您可以向浏览器发送推送通知,只需检查如果此时浏览器关闭会发生什么情况
对于移动应用程序,您可以向移动应用程序发送推送通知,并指示关闭您可以在签署JWT并向客户端发送JWT时在JWT中创建自定义声明。当客户端将令牌发送回您时,请验证特定声明(例如“设备id”)没有更改。这有点棘手,但您可能确实需要在服务器端对会话进行一些处理,即使您试图避免这样做。谢谢。此注释回答非常有用。策略非常好!此解决方案使令牌验证有状态。“有状态”意味着将会话信息保存在服务器中。我建议将状态存储在数据库中,但这并不能使其成为一个安全的解决方案。但是,如果您使用任何类型的微服务体系结构或群集、自动缩放等,则在服务器中跟踪这一点将需要额外的一层