我看了很多文章,看了很多视频,但是有很多矛盾。我尝试避免使用任何外部库,并从头开始构建系统,我已经阅读了有关oAuth 2的信息,但更加令人困惑。
这是我认为直到现在都可以的流程:
一切都很好,但是我遇到了一些问题并有一些疑问:
我希望用户即使在打开新会话后也保持登录状态,因此在令牌过期或关闭浏览器后无需登录。
如果访问令牌过期,应该怎么办?
数据库中应该有一个附加到用户的刷新令牌,当用户登录时(过期7天),该令牌将被添加,然后服务器将使用包含该刷新令牌的cookie进行响应?
在访问令牌过期的新请求上,用户将刷新cookie发送到服务器,如果它与用户数据库刷新令牌匹配,服务器将使用单独的cookie进行响应以更新访问令牌吗?
如果有刷新令牌,则应将其存储在哪里以及什么格式? (Cookie,数据库还是在哪里?)
是否应基于此刷新令牌cookie保持用户登录?如果是httponly,则我无法读取它并设置用户登录状态。该怎么办?
我听说撤销jwt令牌是有问题的。您将如何解决?
您将如何做这件事?请解释一下工作流程,我尽量避免使用本地存储,因为我到处读取对敏感数据不安全的地方。
答案 0 :(得分:0)
我已经实施并部署到了生产系统,这些系统完全可以执行您在此处要询问的事情,因此我认为我有资格为您提供一些指导,以解决您的特定问题并回答您的问题。到目前为止,您在编号列表中列出的流程绝对是正确的路径。我确实理解您的困惑,因为如何解决此问题有很多不同的选择。
除了提供当用户向服务器提交登录表单时向客户端返回新JWT的登录路由外,我还建议实现一个令牌刷新路由,该路由接受从初始接收到的仍然有效的JWT登录过程,并返回具有更新的到期时间的新JWT。此新令牌刷新路由的逻辑应首先通过将其与数据库中的用户进行匹配来验证所提供的JWT仍然有效。然后,它应该使用与登录路由逻辑相同的JWT生成逻辑来生成新令牌。然后,应用程序应覆盖数据库中的访问令牌数据,以便用户用新生成的访问令牌替换旧的访问令牌。一旦旧的访问令牌不再有效,就不必在数据库中保留旧的访问令牌,这就是为什么我建议简单地用一个新的令牌来覆盖它。一旦所有这些操作完成并成功,您就可以将新的JWT返回给客户端,然后客户端现在应该在对服务器进行任何其他经过身份验证的调用时使用该新的JWT来维护与服务器的经过身份验证的交互。该逻辑流程将使用户保持登录状态,因为客户端在调用刷新逻辑之前将具有有效的JWT,而在调用刷新逻辑之后将具有有效的JWT。仅当用户不再能够提供与数据库中的用户相关联的有效访问令牌时,才应将其识别为未登录且未经身份验证。
就cookie而言,无论使用哪种方法来维护客户端上的cookie,都应使用它来设置刷新的访问令牌,就像设置登录时收到的初始访问令牌一样。如果服务器发现访问令牌在将来的某个时候不再有效,例如,如果您的客户端在登录后直到访问令牌过期后的某个时间才被使用,则客户端应识别出服务器响应,表明该响应就是这种情况,并再次向用户提供客户端上的登录流程,以便可以获取新的访问令牌并将其存储在客户端的Cookie中。
我不必担心撤销JWT,而只要让它们失效就可以,如果发现JWT已经失效,则启动一个新的登录流程。另外,我建议不要使用本地存储,而是建议使用会话存储来存储您的JWT,这样您就可以在网站上的用户会话期间使用它,并在关闭浏览器后立即将其删除。这将防止JWT在会话之后继续存在,并应减轻您担心将敏感数据保存在会话存储中的担忧。另外,在生成JWT时,还应注意不要在其中存储任何敏感数据,因为JWT易于逆向工程。这也可以防止任何敏感数据在客户端公开。
编辑:
开发服务器API时要记住的关键是您应该具有两种不同的端点类。一组应该未经身份验证,而一组应该经过身份验证。
经过身份验证的端点集不需要在请求中包含访问令牌。此类端点的一个示例是您的登录端点,它不需要访问令牌,因为它实际上会生成一个访问令牌供以后使用。没有公开敏感信息或重要信息的任何其他端点都可以包括在此类端点中。
未经身份验证的端点集将要求将访问令牌包含在请求中,并且如果未检测到访问令牌或无效的访问令牌,则端点将以401 HTTP response code响应(指示未经授权的请求)。此类端点的一个示例是允许用户更新其个人信息的端点。显然,如果用户无法提供凭据来证明自己是他们要更新其信息的用户,则他们无法更新自己的信息。如果客户端收到带有401响应代码的响应,则这将是客户端为了告诉用户重新登录以获取新的有效访问令牌而需要的信号。如果将客户端编程为定期检查客户端上当前保留的JWT的到期并启动访问令牌刷新,则可以在客户端上避免这种可能性,但是显然,您仍然应该有适当的逻辑来检测和响应401响应代码,以便正确管理客户端用户流。