我是不是正确理解用于身份验证的访问和刷新令牌技术?

Posted

技术标签:

【中文标题】我是不是正确理解用于身份验证的访问和刷新令牌技术?【英文标题】:Does I understand access and refresh token technique for authentication correctly?我是否正确理解用于身份验证的访问和刷新令牌技术? 【发布时间】:2021-01-31 21:23:19 【问题描述】:

在对使用带有访问令牌和刷新令牌的 JWT 进行身份验证进行了一些研究之后。我是这样理解的。

登录后,返回用户访问令牌和刷新令牌(两者使用相同的技术 JWT)。 在数据库中保存刷新令牌(一个用户可以为多个设备拥有多个刷新令牌)。 每当用户发送带有无效访问令牌的请求时,检查刷新令牌并调用另一个 api 以获取新的访问令牌(在客户端执行此操作)。之后,调用 api 再次使用新的 Access Token 获取数据。 如果Refresh Token无效,删除其在数据库中的记录,用户必须重新登录才能获得新的Refresh Token。

我是否正确理解访问和刷新令牌技术?请给我一些建议。提前致谢。

【问题讨论】:

【参考方案1】:

在您列出的 4 个步骤中,有些看起来或多或少正确,而有些则不正确。我将通过给出为什么创建刷新令牌以及它们的主要目的是什么来开始这个答案。

使用仅具有访问令牌的 JWT 模式,当 JWT 令牌过期时可能会出现可用性问题。以银行网站为例。当用户登录时,他会收到一个有一定期限的 JWT 令牌(通常存储在令牌的 claims 部分中的 exp 键下)。如果令牌的有效期为 5 分钟,那么从可用性的角度来看,这意味着网站必须强制用户每 5 分钟手动登录一次。显然,这不是最好的用户体验,因为这意味着当令牌过期时恰好处于某个业务流程中间的用户可能会失去所有的工作。这是刷新令牌介入以缓解此问题的地方。

将 JWT 模式与刷新令牌一起使用意味着用户会同时收到一个访问权限一个刷新令牌。这里的典型工作流程可能是:

登录后,返回用户访问令牌和刷新令牌(两者使用相同的技术 JWT)。当访问令牌设置为过期(例如 15 分钟)时,接收方会记录下来。 随着访问令牌到期(例如 10 分钟)的临近,UI 会将刷新令牌发送到后端以获取新的访问令牌(和刷新令牌)。这可以明确地完成,例如在显示弹出窗口询问用户是否要继续的网站上。或者它可以在隐身模式下完成,在后台进行 REST 调用以获取新的访问令牌。 对于无法使用刷新令牌获取新访问令牌的边缘情况,下一个需要身份验证的用户操作将失败。在这种情况下,用户必须重定向到登录页面。但是,由于这种情况通常很少见,因此不会取消刷新令牌模式的资格。

我还要指出,将访问/刷新令牌存储在数据库中很大程度上违背了 JWT 模式的目的。使用 JWT 的一个主要原因是它将用户会话状态推送到应用程序之外并传递给用户。通过将令牌存储在数据库中,您完全可以使您的用户会话非常有状态,这具有各种潜在的缺点。考虑使用上面建议的工作流程来避免这样做。

【讨论】:

我明白了。但是在这种情况下,Access Token 和 Refresh Token 有什么区别呢?在您的情况下,刷新令牌只是访问令牌的长期版本。如果用户想要使所有活动的刷新令牌过期(也就是注销所有会话),这不能用刷新令牌来完成,只存储在客户端。 @QuangKhảiĐàm 一个典型的设置可能是刷新令牌只能用于获取新的访问令牌。它不能用于执行任何其他用户操作(需要访问令牌本身)。强制通用注销是另一回事。一种方法是只使用服务器端逻辑来拒绝在某个日期/时间之前发布的任何 JWT。 所以如果 Refresh Token 被盗用,整个系统都会被盗用。因为没有办法撤销Refresh Token(有了Refresh Token,我可以得到任何我想调用api的Access Token)。你能为我解释一下这种情况吗?谢谢 我已经在上面的评论中做了。缺少令牌确实意味着您的整个系统已“受损”;这是错误的词。最坏的情况是您的服务必须提示用户再次登录/验证,仅此而已。 我的意思是刷新令牌。如果它只是存储在客户端,它可能会受到损害【参考方案2】:

在我看来,您的刷新令牌需要存储并与设备和用户相关联。

示例: 用户在设备 A 中登录

    呼叫登录端点 验证用户是否有效
      如果有效,则生成与用户 ID 和设备关联的刷新令牌 身份证 将所需数据存储到您的表或存储引擎 (user_sessions..etc) 用户 ID | device_id |刷新令牌 | expires_at 返回带有 access_token、refresh_token、access_token_expires_at、refresh_token_expires_at 的负载 前端,存储payload
    消耗资源时,请检查以下内容
      如果 refresh_token_expires_at > 现在然后将它们注销,则表明您的会话已超时(或者您可以拥有一个永不过期的 refresh_token.. 例如 refresh_token_expires_at 可以为 0) 如果 access_token_expires_at > 现在调用刷新令牌端点以及您的有效负载。 在刷新端点上,验证调用并根据存储的数据检查刷新令牌。
        如果刷新令牌对此用户+设备有效,则生成新的 access_token 返回 access_token 及其 expires_at 如果刷新令牌无效,则返回无效 前端会将用户注销。

** 在任何情况下,如果刷新令牌被泄露,它将仅适用于该特定设备/用户。然后,用户可以从他们的列表中停用或删除该设备。此操作将在下一次刷新调用时使 refresh_token 无效。

【讨论】:

以上是关于我是不是正确理解用于身份验证的访问和刷新令牌技术?的主要内容,如果未能解决你的问题,请参考以下文章

OAuth 2.0应该用于身份验证超时吗?

JWT 身份验证方案中的刷新令牌是不是应该使用与访问令牌不同的秘密进行签名?

访问/刷新令牌混淆

Android 刷新令牌

JWT身份验证中刷新令牌的正确实现是啥

Cognito 用户池:如何使用刷新令牌刷新访问令牌