使用 JWT 令牌时,我应该如何处理 RESTful 身份验证?

How should I handle RESTful authentication while using JWT tokens?

看了很多文章,看了很多视频,矛盾的地方很多。我尽量避免使用任何外部库并从头开始构建系统,我已经阅读了有关 oAuth 2 的内容,但它更令人困惑。

这是我目前认为还可以的流程:

  1. 用户使用电子邮件和密码填写表单并提交。
  2. 如果密码匹配,服务器将验证密码,并使用带有签名 jwt 令牌的 httponly cookie 进行响应,该令牌将在 10 后过期 分钟。 (我知道我必须保护它免受 csrf 攻击)
  3. 用户登录后,他向服务器发出的每个新请求都会自动在 header 中发送 cookie,并且 服务器将验证令牌。

一切都很好,但我遇到了一些问题并有一些疑问:

我希望用户即使在打开新的 session 后仍保持登录状态,因此在令牌过期或关闭浏览器时无需登录。

如果访问令牌过期会怎样?

数据库中应该有一个附加到用户的刷新令牌,当用户登录并在 7 天前到期时添加该令牌,然后服务器将使用包含该刷新令牌的 cookie 进行响应?

在访问令牌过期的新请求中,用户将刷新 cookie 发送到服务器,如果它与用户数据库刷新令牌匹配,服务器将响应一个单独的 cookie 来更新访问令牌?

如果有刷新令牌,您应该将其存储在什么位置以及什么格式? (cookie、数据库或哪里?)

我应该根据这个刷新令牌 cookie 让用户保持登录状态吗?如果是 httponly,我无法读取它并设置用户已登录的状态。我应该怎么做?

我听说撤销 jwt 令牌是有问题的。你会如何解决它?

你会怎么做这整个事情?请解释一下工作流程,我尽量避免本地存储,因为我到处都读到对敏感数据不安全。

我已经实施并部署到生产系统中,这些系统完全可以执行您在这里询问的各种事情,因此我认为我有资格为您提供一些指导来解决您的特定问题并回答您的问题。到目前为止,您在上面编号列表中列出的流程绝对是正确的路径。我确实理解你从那里开始的困惑,因为有很多不同的选择来解决这个问题。

除了在用户向服务器提交登录表单时向客户端提供 return 新 JWT 的登录路由外,我还建议实现一个接受仍然有效的 JWT 的令牌刷新路由这是从初始登录过程中收到的,return 是一个新的 JWT,具有更新的到期时间。这个新令牌刷新路由的逻辑应该首先通过将提供的 JWT 与数据库中的用户匹配来验证它是否仍然有效。然后,它应该使用与登录路由逻辑相同的 JWT 生成逻辑来生成一个新令牌。然后,应用程序应该为用户用新生成的访问令牌替换旧的访问令牌覆盖数据库中的访问令牌数据。一旦旧的访问令牌不再有效,就没有必要在数据库中保留它,这就是为什么我建议用一个新的简单地覆盖它。一旦所有这些都完成并成功,您可以 return 新的 JWT 到客户端,然后客户端现在应该在对服务器进行任何额外的经过身份验证的调用时使用该新的 JWT 来维护与服务器的经过身份验证的交互。此逻辑流将使用户保持登录状态,因为客户端在调用刷新逻辑之前将具有有效的 JWT,并且在调用刷新逻辑之后将具有有效的 JWT。只有当用户不再能够提供与数据库中的用户相关联的有效访问令牌时,才应将用户识别为未登录且未通过身份验证。

就 cookie 而言,无论您使用哪种方法在客户端维护 cookie,都应该用于设置刷新的访问令牌,因为它用于设置您在登录时收到的初始访问令牌。如果服务器发现访问令牌在未来的某个时间点不再有效,例如,如果您的客户端在登录后直到访问令牌过期后的某个时间才被使用,那么客户端应该识别一个服务器响应,表明这是这种情况,并在客户端再次向用户呈现登录流程,以便可以获取新的访问令牌并将其存储在客户端的 cookie 中。

我不会担心撤销 JWT,而是让它们在撤销时过期,并在发现 JWT 已过期时启动新的登录流程。此外,我建议不要使用本地存储,而是使用会话存储来存储您的 JWT,这样您就可以在用户在网站上的会话期间拥有它,并在浏览器关闭后立即将其删除。这将防止 JWT 在会话之外持续存在,并且应该减轻您对在会话存储中保存敏感数据的担忧。此外,在生成 JWT 时,您还应该注意不要在其中存储任何敏感数据,因为 JWT 很容易被逆向工程。这也可以防止任何类型的敏感数据暴露在客户端上。

编辑:

开发服务器 API 时要记住的关键是您应该有两个不同的 class 端点。一组应未经身份验证,一组应经过身份验证。

经过身份验证的端点集不需要在请求中包含访问令牌。此 class 端点的一个示例是您的登录端点,它不需要访问令牌,因为它实际上会生成一个访问令牌供您稍后使用。任何其他不公开敏感或重要信息的端点都可以包含在此 class 个端点中。

未经身份验证的端点集需要在请求中包含访问令牌,如果未检测到访问令牌或访问令牌无效,则端点将以 401 HTTP response code 响应(表示未经授权的请求). class 端点的一个示例是允许用户更新其个人信息的端点。显然,如果用户不能提供凭证来证明他们是他们试图更新其信息的用户,那么他们就不能更新他们自己的信息。如果客户端收到带有 401 响应代码的响应,这将是客户端需要的信号,以便告诉用户重新登录,以便可以检索新的有效访问令牌。如果客户端被编程为定期检查当前保存在客户端上的 JWT 的到期时间并启动访问令牌刷新,则可以在客户端上避免这种可能性,但显然您仍然应该有适当的逻辑来检测和响应401 响应代码,以便正确管理客户端用户流。