在 NodeJS 中一次只允许从一台设备登录 [英] Only allow signing in from one device at a time in NodeJS

查看:24
本文介绍了在 NodeJS 中一次只允许从一台设备登录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 JWT 进行身份验证.但是我不希望用户从多个设备登录.我如何确保这一点?

I am using JWT for authentication. However I do not want the user to be logged in from multiple devices. How do I ensure this?

现在 - 我能想到的就是将 JWT 存储到 DB 中,然后检查它是否存在.如果它存在,它是在什么时间生成的.如果时间过多 - 我们会重新生成令牌并传递回第二台设备.

Right now - All I can think of is to store the JWT into DB and then check if it exists . And if it exists, what was the time it was generated at. If too much time - we go and regenerate the token and pass on back to the 2nd device.

推荐答案

这几乎是你唯一的选择,JWT 是故意无状态的.类似于没有类似技术就无法真正进行服务器端注销

That's pretty much your only option, the JWT is pretty stateless on purpose. Similar to how you can't really do a server side logout without similar technique

正如 jfriend 指出的那样,单独存储 JWT 是不够的.您需要做的是确保下次用户请求登录时,他们还没有收到未过期的 JWT.

As jfriend points out, storing the JWT alone is insufficient. What you need to do with it is ensure that the next time a user requests login, that they don't already have an unexpired JWT issued to them.

为了完整性而遍历流程:

Going through the flow for completeness:

案例 1:用户未在任何地方登录.在这种情况下,JWT 被发布和存储.可能在用户记录中以便于检索.

Case 1: User isn't logged in anywhere. In this case, JWT is issued and stored. Possibly in the user record for easy retrieval.

案例 2:用户尝试在另一台设备上登录.无论您是让他们明确注销第一台设备还是为他们这样做,您现在都必须将该存储的令牌发送到已撤销令牌的列表中.在确定令牌是否有效时,您的令牌验证逻辑必须考虑该列表.

Case 2: User tries to log in on another device. Whether you make them explicitly log out of the first device or do it for them, you have to now send that stored token into a list of revoked tokens. Your token validation logic will have to take that list into account when determining if a token is valid or not.

/* 进一步说明 */

/* Further clarification */

我觉得更多细节可能对人们有用,所以我将稍微介绍一下实现.

I feel like a bit more detail might be useful for folks, so I'm going to go into implementation a bit.

** 未经身份验证的请求 **

** Unauthenticated requests **

这不应该改变,但值得一提的是,我假设您有需要身份验证的路由,并且对那些不包含活动且有效 JWT 的路由的请求会被 401 拒绝(并且可能提供了 URL到登录网址).

This shouldn't change, but it's worth mentioning that I'm assuming you have routes that require authentication, and requests to those routes which do not include an active and valid JWT get rejected with a 401 (and probably provided the URL to the login url).

登录

登录逻辑始终包含用户查找,因此如上所述,此应用程序中的流程应包含该查找,但在将用户登录到应用程序之前,您将检查是否已经为该用户分配了令牌没有过期.

Login logic always includes a user lookup, so as described above, the flow in this application should include that lookup, but before logging the user in the application you will check to see if there's already an assigned token to the user which has not expired.

如果尚未为用户分配令牌,则按照通常的方式检查凭据,生成 JWT(带有 exp 标题以指示有效负载中的到期时间),将该令牌保存回用户文档/记录中备查.

If there is not a token already assigned to the user, then check credentials however you normally would, generate a JWT (with an exp heading to indicate expiration time in the payload), save that token back in the user document/record for future reference.

如果有 分配的令牌也未过期,那么您要么必须将用户从另一台设备上注销(稍后再详细介绍),然后将他们登录到当前设备,否则您必须拒绝登录尝试并让该人退出新设备.我认为前一种方法对用户更友好,但这取决于您的应用程序的需求.

If there is an assigned token which is also unexpired, then you either have to log the user out of the other device (more on that in a second), and log them in to the current device, or else you have to reject the login attempt and keep the person logged out of the new device. I think the former approach is more user friendly, but it depends on the needs of your application.

退出

使用 JWT,确保用户无法使用已颁发令牌的唯一方法是在有效负载中包含过期时间 (exp),并使用验证器来检查,或者在服务器上知道哪些令牌不再有效并检查它们.最强大的解决方案两者兼而有之.

With JWT, the only way to guarantee a user is unable to use an issued token is to either include an expiration time (exp) in the payload, and use a verifier that checks that, or to know on the server which tokens are no longer valid and check against them. The most robust solutions do both.

因此,假设您已经在处理过期问题,则可以通过在某处创建已撤销令牌列表来处理显式注销功能.例如,如果您使用 MongoDB,您将创​​建一个集合来存储它们.理想情况下,您还可以为每个设置为过期日期后某个时间点的 TTL 设置一个 TTL,以便 Mongo 将驱逐无论如何过期的令牌,以节省您的时间和空间.

So, assuming you're handling the expiration already the explicit logout feature would be handled by creating a revoked tokens list somewhere. If you're using MongoDB, for example, you'd create a collection to store those. You'd ideally also set a TTL on each one that is set to some point after the expiration date, so that Mongo will evict tokens that are otherwise expired anyway, to save yourself time and space.

如果您在新的登录请求中执行自动注销,当您将新令牌保存在用户文档中时,您将按此逻辑将旧令牌放入已撤销的令牌列表中.

If you're doing the auto-logout on a new login request, you'll hit this logic to place the old token into the revoked tokens list when you save the new token in the user's document.

经过身份验证的用户也应该可以访问注销路由,以便在他们需要时显式注销,无论您是否执行自动注销.

The logout route should also be reachable by authenticated users, to explicitly logout if they want, regardless of whether you do the auto logout or not.

经过身份验证的请求

此时,您应该可以合理地确定用户只能在一台设备上登录.但是,您还需要确保他们不会尝试使用已撤销的令牌发出请求.

By this point you should be reasonably certain that users can only login on one device. However, you also need to make sure that they aren't trying to make a request with a revoked token.

然后,您的通用路由安全中间件还需要检查已撤销的令牌列表,以查看客户端提供的令牌在检查以确保它没有过期后是否在所述列表中(因为可以在验证时检查过期,保存到数据库的往返.

Your generalized route security middleware would then need to also check the revoked token list to see if the token offered by the client is on said list after checking to make sure it's not expired (since the expiry can be checked upon validation, saving a round-trip to the DB.

这篇关于在 NodeJS 中一次只允许从一台设备登录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆