Session 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

我们当前的应用程序使用HTTP会话,我们想用JWT取代它

该设置只允许每个用户进行一次会话。这意味着:

  • 用户在设备1上登录
    • 用户登录到设备1(创建新会话)
  • 用户在设备2上登录
    • 用户在设备2上登录(创建新会话)
    • 用户未在设备1上登录(会话被破坏)
  • 这是因为会话id和用户id之间存在服务器端关系


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

  • 用户在设备1上登录
    • JWT令牌签名包含计数器+1(并将新计数器保存到数据库)
  • 用户在设备2上登录
    • JWT的签名包含计数器+1,它会增加并保存到db
  • 现在,对于每个请求,我必须检查传入的签名对于当前计数器值是否正确

    这不知怎么地使它有状态<代码>:(

    但是…JWT的优点之一是,不需要访问任何数据库或会话存储来验证令牌



    是否有其他防止并发登录的解决方案?可能是在没有数据库访问的情况下工作并保持无状态的解决方案?

    您非常接近该解决方案

    要做到这一点,您需要以下几点:
    1.在令牌中包括iat(令牌发出的时间)
    2.在某个地方存储用户上次登录的时间,例如在用户配置文件中


    现在,在验证令牌时,请进行额外检查:iat(在发出)必须在或晚于上次登录时间。这意味着旧令牌无效。

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

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

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

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

    其想法是,此表可能比完整的用户表小得多。只有最近登录了多个设备的用户才会在此表中有一个条目。因此,扫描此表是有效的。以正常方式验证令牌后,请检查iat(在下发时)不是在用户会话epoc之前。如果是,则该设备不是最近登录的设备

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


    通过定期删除早于任何令牌的最大生存期的项来维护此表。

    首先,在会话中使用JWTs时,必须定义:

    • 无状态令牌:包含令牌内的所有会话数据。此 这样你就不需要把它存放在任何地方了
    • Steteful令牌:包含会话id。当服务器收到 令牌他将需要检索有关会话的信息
    如果您使用有状态解决方案使令牌无效,您可以向DB查询该用户的最后一个会话ID,并与收到的令牌进行比较。
    在无状态解决方案中,正如其他答案所指出的,您可能需要在某个地方持久化状态。但是与有状态令牌相比,您只需要存储您建议的计数器或@thetahaan建议的“last_login”

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

    • 用户在其他设备中登录
    • 一段时间过去了

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

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

        那么,每次用户登录时,您都会按设备类型保存最后一次登录,并向所有连接的相同类型设备(假定为一个)发送推送通知

        在这种情况下,在浏览器上,您可以向浏览器发送推送通知,只需检查如果此时浏览器关闭会发生什么情况


        对于移动应用程序,您可以向移动应用程序发送推送通知,并指示关闭

        您可以在签署JWT并向客户端发送JWT时在JWT中创建自定义声明。当客户端将令牌发送回您时,请验证特定声明(例如“设备id”)没有更改。这有点棘手,但您可能确实需要在服务器端对会话进行一些处理,即使您试图避免这样做。谢谢。此注释回答非常有用。策略非常好!此解决方案使令牌验证有状态。“有状态”意味着将会话信息保存在服务器中。我建议将状态存储在数据库中,但这并不能使其成为一个安全的解决方案。但是,如果您使用任何类型的微服务体系结构或群集、自动缩放等,则在服务器中跟踪这一点将需要额外的一层