每次使用 JWT 登录时允许一个并发用户
Posted
技术标签:
【中文标题】每次使用 JWT 登录时允许一个并发用户【英文标题】:Allow one concurrent user per login with JWT 【发布时间】:2017-02-14 07:48:17 【问题描述】:我们正在使用 Laravel/php 开发一个应用程序,我们希望使用按用户付费的定价模型。为此,我们必须确保一个帐户只能由一个并发用户使用。我们使用 JWT 进行身份验证,它是无状态的,所以我不能使用会话。
为了确保一个并发登录,我可以附上浏览器代理或 IP,但两者都不是唯一的,它们可能会在例如多次出现。办公室。我也可以发送 MAC 地址,但这不是最简单的方法。
是否有其他解决方案可以确保每个用户使用 JWT 进行一次并发登录?
【问题讨论】:
你可能会从这个 RFC 提案中得到一些想法:tools.ietf.org/html/draft-jones-oauth-token-binding-00 【参考方案1】:我认为这个问题的简单答案是否定的,你不能通过 JWT 做到这一点并保持服务器无状态。但是,如果您将设置与访问令牌和刷新令牌一起使用,您可能会实现如下效果:
-
用户登录,您将刷新令牌存储在数据库中
访问令牌过期。在从刷新令牌发出新的访问令牌之前,请先检查帐户是否仍然正常,还要将刷新令牌与数据库中的令牌进行比较。确保它们匹配。
第二个用户使用相同的帐户登录。将问题刷新令牌存储在数据库中并覆盖旧的刷新令牌。 (每个帐户一个存储的刷新令牌。)
第一个用户访问令牌再次过期。这次在 DB 中有另一个 Refresh Token,并且没有为该用户颁发新的 Access Token。
这将产生一个登录流程,其中最新登录的用户可以使用您的服务。如果实际上是同一用户更改设备或重新启动浏览器会话,这将很方便。与例如 Spotify 的“追逐流”处理并发收听的方式进行比较。
【讨论】:
SPA 应用程序如何使用隐式流意味着在这种情况下没有刷新令牌的概念。 ? 如果我正确理解了第 3 点和第 4 点,如果第一个用户的令牌未过期并且第二个用户登录,那么两个用户将保持登录状态,直到第一个用户的令牌过期? 在SPA中token也可以过期,app只需要知道如何刷新它,并且在后台过期前刷新即可。只要记住设置一个足够短的过期时间,但足以让每个应用不时刷新它。 @Hiren 是对的,将其与取决于应用程序性质的合理的低到期时间相结合将减少 2 个同时用户登录的可能性,但同样不能完全消除它。【参考方案2】:我能想到的唯一答案:
登录时: 您的数据库中的“用户”有一个值 = activeJwt
用户登录并创建 JWT 令牌,将 JWT 字符串复制到值 activeJWT 在您的数据库中并将其发送给用户。 如果您在另一台设备上登录相同的交易,并且 activeJWT 值发生了更改
在所有需要登录匹配用户 JWT-string 和 activeJWT 的请求上,如果他们 不匹配意味着另一个设备在使旧令牌无用后登录。
【讨论】:
好主意,它也有效,谢谢!由于我使用的是 Spring,因此我使用了HandlerInterceptorAdapter
来测试 JWT 与存储在数据库中的 JWT。
那么您将失去 jwt 的好处,即您无需访问数据库来获取用户详细信息并检查每个请求的用户是否经过身份验证。
简单而优雅【参考方案3】:
我现在在不使用 JWT 和使用密码授权令牌的 OAuth2 身份验证的情况下进行测试。在 1 个客户端内,用户只能通过一次登录使用该应用程序,如果他在另一个会话/设备上登录,则另一个登录(令牌)将不再有效。当我想允许一个用户多次登录(例如网络应用和移动应用)时,我可以使用多个客户端。
【讨论】:
【参考方案4】:无论如何,您需要将令牌存储在数据库中。 为此,您将需要超快速存储。 Redis 将是完美的。 在新登录时,只需将令牌替换为新的。 每次用户发出请求时,检查令牌是否与您在 redis 中的令牌匹配。如果没有,那就把他踢出去。
【讨论】:
【参考方案5】:在不保存服务器状态的情况下,我唯一能想到的就是禁用在令牌生命周期内签署新令牌的功能。
【讨论】:
这也将阻止用户在另一台设备上再次登录,或者在令牌的生命周期内重新启动浏览器。以上是关于每次使用 JWT 登录时允许一个并发用户的主要内容,如果未能解决你的问题,请参考以下文章