在更改密码和在node.js中注销时使JWT无效的最佳做法?

Gop*_*iva 64 javascript token auth-token node.js jwt

我想知道在更改密码/注销时不使用db而使JWT无效的最佳实践.

我有以下想法通过点击用户数据库处理上述2个案例.

1.密码更改,我检查存储在用户db中的密码(散列).

2.注销时,我在用户数据库中保存了最后注销时间,因此通过比较令牌创建时间和注销时间,我可以使这种情况无效.

但是这两种情况是以每次用户点击api时命中用户数据库为代价的.任何最佳实践表示赞赏.

更新: 我不认为我们能够在没有命中数据库的情况下使JWT无效.所以我想出了一个解决方案.我已经发布了我的答案,如果您有任何疑虑,欢迎您.

Gop*_*iva 69

使用No Refresh令牌时:

1.更改密码时:当用户更改密码时,请注意用户数据库中的更改密码时间,因此当更改密码时间大于令牌创建时间时,令牌无效.因此剩余的会话很快就会被注销.

2.当用户注销时:当用户注销时,将令牌保存在单独的数据库中(例如:InvalidTokenDB并在令牌过期时从Db中删除令牌).因此,用户从相应的设备注销,他在其他设备中的会话保持不受干扰.

因此,在使JWT无效时,我遵循以下步骤:

  1. 检查令牌是否有效.
  2. 如果有效,请检查它是否存在于invalidTokenDB(存储注销令牌的数据库中,直到其到期时间).
  3. 如果它不存在,则检查令牌创建时间并更改用户db中的密码时间.
  4. 如果更改密码时间<令牌创建时间,则令牌有效.

关注上述方法:

  1. 对于每个api请求,我需要遵循上述所有步骤,这可能会影响性能.

使用刷新令牌时:访问令牌到期为1天,刷新令牌作为终身有效性

1.更改密码时:当用户更改密码时,请更改用户的刷新令牌.因此剩余的会话很快就会被注销.

2.当用户注销时:当用户注销时,将令牌保存在单独的DB中(例如:InvalidTokenDB并在令牌过期时从Db中删除令牌).因此,用户从相应的设备注销,他在其他设备中的会话保持不受干扰.

因此,在使JWT无效时,我遵循以下步骤:

  1. 检查令牌是否有效
  2. 如果有效,请检查令牌是否存在于InvalidTokenDB中.
  3. 如果不存在,请使用userDB中的刷新令牌检查刷新令牌.
  4. 如果等于,则为有效令牌

关注上述方法:

  1. 对于每个api请求,我需要遵循上述所有步骤,这可能会影响性能.
  2. 如何使刷新令牌无效,因为刷新令牌没有效力,如果黑客使用它,仍然认证是有效的,请求将始终成功.

注意:虽然Hanz建议在基于令牌的身份验证使用Refesh令牌来保护刷新令牌的方法是安全的吗?,我无法理解他在说什么.任何帮助表示赞赏.

所以,如果有人有好的建议,欢迎您提出意见.

更新: 我正在添加答案,因为您的应用程序不需要刷新令牌,终身有效期.这个答案由Sudhanshu提供(/sf/users/284384131/).谢谢Sudhanshu.所以我相信这是最好的方法,

当需要无刷新令牌且访问令牌没有到期时:

当用户登录时,在其用户数据库中创建一个没有到期时间的登录令牌.

因此,在使JWT无效时,请按照以下步骤操作,

  1. 检索用户信息并检查令牌是否在他的用户数据库中.如果允许的话.
  2. 用户注销时,仅从其用户数据库中删除此令牌.
  3. 当用户更改其密码时,从他的用户数据库中删除所有令牌并要求他再次登录.

因此,使用这种方法,您不需要在数据库中存储注销令牌,直到它们到期,也不需要在更改上述情况下所需的密码时存储令牌创建时间.但是我相信这种方法只有在您的应用程序具有不需要刷新令牌并且令牌没有到期的要求时才有效.

如果有人担心这种方法,请告诉我.欢迎你的评论:)

  • 不查看数据库/数据存储区是否违背了JWT的目的? (47认同)
  • @Metalstorm:这个讨论是关于如何在密码更改或用户注销(使用或不使用刷新令牌)时使JWT无效.如果您知道在没有数据库交互的情况下处理此案例的任何方法,欢迎您发布:) (11认同)

Dev*_*Fox 14

我不知道如果不以某种方式涉及数据库而任意使令牌无效.

如果可以在多个设备上访问您的服务,请注意方法2.考虑以下场景......

  • 用户使用iPad登录,Token 1发布并存储.
  • 用户登录网站.令牌2发行.用户注销.
  • 用户尝试使用iPad,在用户从网站注销之前发出了令牌1,令牌1现在被视为无效.

您可能想要查看刷新令牌的想法,尽管这些也需要数据库存储.

另请参阅此处以了解有关类似问题的SO讨论,特别是IanB的解决方案可以节省一些db调用.

建议的解决方案就 个人而言,这就是我接近它的方式......用户进行身份验证,使用短期到期(例如15分钟)的访问令牌发布,刷新令牌有效期更长或无限期.将此刷新令牌的记录存储在db中.

每当用户"处于活动状态"时,每次都会发出一个新的身份验证令牌(每次有效15分钟).如果用户超过15分钟未激活然后发出请求(因此使用过期的jwt),请检查刷新令牌的有效性.如果它有效(包括数据库检查),则发出新的身份验证令牌.

如果用户在设备上或通过网站'注销',则销毁两个访问刷新令牌客户端,并且重要地撤销所使用的刷新令牌的有效性.如果用户在任何设备上更改其密码,则撤消所有刷新令牌,强制他们在访问令牌过期后再次登录.这确实留下了一个"不确定性的窗口",但这并不是每次都没有击中数据库时不可避免的.

使用这种方法还可以让用户能够"撤销"对特定设备的访问,如果需要,可以看到许多主要的Web应用程序.


Amr*_*ani 7

我不确定我是否在这里遗漏了一些东西,但我发现接受的答案比必要的更复杂.

我看到db必须被命中以验证或使每个api请求的令牌无效,但是总体过程可能更简单,因为我在这里看到的东西.

每当创建一个jwt时,即在登录或更改/重置密码期间,将带有用户ID的jwt插入表中并为每个jwt维护一个jti(基本上是一个uuid数).同样的jti也进入jwt有效载荷.有效地jti唯一地标识一个jwt.当从多个设备或浏览器访问帐户时,用户可以同时具有多个jwts,在这种情况下,jti区分设备或用户代理.

所以表模式是,jti | 用户身份.(和课程的主键)

对于每个api,检查jti是否在表中,这意味着jwt是有效的.

当用户更改或重置密码时,从db中删除该userId的所有jti.创建一个带有新jti的新jwt并将其插入表中.除了更改或重置密码的会话外,这将使所有其他设备和浏览器的所有会话无效.

当用户注销时,删除该用户的特定jti但不是全部.将有一个单一登录但没有一个登出.因此,当用户注销时,他不应该从所有设备注销.但是,删除所有jtis也会从所有设备注销.

所以这将是一个表,没有日期比较.如果使用或不使用刷新令牌,情况也是如此.

然而,为了最小化数据库干扰和可能的延迟,缓存使用肯定有助于缓解处理时间的问题.

注意:请说明您是否正在投票.

  • 如果您必须为每个 API 调用检查数据库,那么感觉 JWT 的全部意义都是多余的。不妨使用会话。 (2认同)