1. 在更改密码时,我检查存储在用户数据库中的密码(已经哈希)。 2. 在注销时,我在用户数据库中保存最后一次注销的时间,因此通过比较令牌创建时间和注销时间,我可以使其无效。
但这2个情况的代价是每当用户调用API时都要访问用户数据库。欢迎分享任何最佳实践。
更新: 我不认为我们可以在没有访问数据库的情况下使JWT无效。所以我想到了一个解决方案,如果您有任何疑虑,请查看我的答案。
当未使用刷新令牌时:
1.在更改密码时: 当用户更改密码时,在用户数据库中记录更改密码的时间,因此当更改密码的时间大于令牌创建时间时,令牌就无效了。因此,剩余会话将很快注销。
2.当用户退出登录时: 当用户退出登录时,将令牌保存在单独的数据库中(例如:InvalidTokenDB),并在令牌过期时从数据库中删除令牌。因此,用户从相应设备注销登录后,他在其他设备上的会话不受影响。
因此,在使JWT失效时,我按照以下步骤操作:
上述方法的问题:
当使用刷新令牌时: 访问令牌有效期为1天,刷新令牌有效期为终身
1.在更改密码时: 当用户更改密码时,更改用户的刷新令牌。因此,剩余会话将很快注销。
2.当用户退出登录时: 当用户退出登录时,将令牌保存在单独的数据库中(例如:InvalidTokenDB),并在令牌过期时从数据库中删除令牌。因此,用户从相应设备注销登录后,他在其他设备上的会话不受影响。
因此,在使JWT失效时,我按照以下步骤操作:
因此,如果有人有好的建议,欢迎您的评论。
更新: 我添加答案,以防止您的应用程序需要具有寿命到期的刷新令牌。此答案由Sudhanshu(https://stackoverflow.com/users/4062630/sudhanshu-gaur)提供。感谢Sudhanshu。所以我认为这是最好的方法, 不需要刷新令牌并且访问令牌无到期时间时:当用户登录时,在他的用户数据库中创建一个无到期时间的登录令牌。
因此,在使JWT失效时,请按照以下步骤进行:
因此,使用这种方法,您不需要在数据库中存储注销令牌,直到它们过期,也不需要在更改密码时存储令牌创建时间,而这在上述情况下是必需的。但是,我认为只有在您的应用程序要求不需要刷新令牌且访问令牌没有到期时间的情况下,此方法才有效。
如果有人对此方法有疑虑,请告诉我。欢迎您的评论:)
目前我所知道的方法中,没有一种可以在不涉及数据库的情况下任意使令牌失效的方法。
如果您的服务可以在多个设备上访问,请小心使用第二种方法。考虑以下场景...
- 用户使用iPad登录,Token 1被颁发并存储。
- 用户在网站上登录。Token 2被颁发。用户退出登录。
- 用户尝试使用iPad,Token 1是在用户从网站退出登录之前颁发的,现在被视为无效。
您可能需要查看“刷新令牌”的概念,尽管这些也需要数据库存储。
此外,还可以参见此处,其中进行了一次良好的SO讨论,讨论了类似的问题,特别是IanB的解决方案可以节省一些db调用。
建议的解决方案 就我个人而言,我会这样做...用户进行身份验证后,颁发一个带有短期到期时间(例如15分钟)和长期有效或无限期的刷新令牌。在数据库中存储此刷新令牌的记录。
每当用户“活动”时,每次颁发一个新的身份验证令牌(每次有效期为15分钟)。如果用户超过15分钟没有活动,然后进行请求(因此使用已过期的JWT),请检查刷新令牌的有效性。如果它有效(包括db检查),则颁发新的身份验证令牌。
如果用户在设备或网站上“注销”,则在客户端销毁访问刷新令牌,并重要地撤销所使用的刷新令牌的有效性。如果用户在任何设备上更改其密码,则撤销其所有刷新令牌,强制他们在访问令牌过期后再次登录。这确实留下了一个“不确定窗口”,但是在不每次命中db的情况下无法避免。
使用此方法还可以打开用户有可能“吊销”特定设备访问权限的可能性,就像许多主要Web应用程序所看到的那样。
我不确定我是否漏掉了什么,但我发现被接受的答案比必要的复杂。
我发现每次API请求都需要命中数据库来验证或使token失效,然而总体过程可以更简单。
每当创建JWT时,即在登录或更改/重置密码期间,将具有用户ID的JWT插入到表中,并为每个JWT维护一个jti(基本上是UUID编号)。同样的jti也进入JWT负载。有效地,jti唯一标识JWT。当从多个设备或浏览器访问帐户时,用户可能同时拥有多个JWT,在这种情况下,jti区分设备或用户代理。
因此,表模式将是,jti | userId。(当然还有主键)
对于每个API,检查jti是否在表中,这意味着JWT是有效的。
当用户更改或重置密码时,从数据库中删除该userId的所有jti。创建并插入带有新jti的新JWT到表中。这将使除更改或重置密码的设备之外的所有其他设备和浏览器的所有会话无效。
当用户退出时,删除该用户的特定jti,但不是所有jti。会有单点登录但没有单点注销。因此,当用户注销时,他不应从所有设备注销。但是,删除所有jtis也将从所有设备注销。
因此,这将是一个表,没有日期比较。如果使用刷新令牌或不使用刷新令牌,则情况相同。
然而,为了最小化数据库干扰和可能的延迟,缓存使用肯定会有所帮助,以缓解处理时间问题。
注意:如果您向下投票,请说明原因。
我完全同意@gopinath的答案,只想补充一点,当所有令牌过期时,您还应该删除更改密码时间,例如假设您设置了每个令牌的3天到期时间,现在除了正常保存更改密码时间之外,您还可以将其到期时间设置为3天,因为显然在此之前的令牌将过期,因此无需再次检查每个令牌的到期时间是否大于更改密码时间。