Passport.js RESTful auth

如何使用 passport.js 通过 RESTful API 而不是通过 Web 界面来处理身份验证(例如,本地和 Facebook) ?

具体的关注点是处理从回调到 RESTful 响应(JSON)的数据传递,而不是使用典型的 res.send ({ data: req.data }) ,设置一个初始/登录端点重定向到 Facebook (/login 不能通过 AJAX 访问,因为它不是 JSON 响应——它是一个带回调的重定向到 Facebook)。

我已经找到了 https://github.com/halrobertson/test-restify-passport-facebook,但我无法理解它。

此外,passport.js 如何存储身份验证凭据?服务器(还是服务?)是由 MongoDB 支持的,我期望凭证(login & salted hash of-被存储在那里,但是我不知道 passport.js 是否有这种功能。

49581 次浏览

这里有很多问题,看起来即使这些问题是在 Node 和 passport.js 上下文中提出的,真正的问题更多的是关于工作流,而不是如何使用特定的技术。

让我们使用@Keith 示例设置,为了增加安全性稍作修改:

  • 位于 https://example.com的 Web 服务器提供一个单页 Javascript 客户端应用程序
  • https://example.com/api的 RESTful Web 服务为富客户端应用程序提供服务器支持
  • 在 Node 和 passport.js 中实现的服务器。
  • 服务器有一个带有“ users”表的数据库(任何类型)。
  • 提供了用户名/密码和 Facebook Connect 作为身份验证选项
  • 富客户机将 REST 请求发送到 https://example.com/api
  • 可能还有其他客户端(例如手机应用程序)使用 https://example.com/api的 Web 服务,但不知道 https://example.com的 Web 服务器。

注意,我使用的是安全 HTTP。在我看来,对于任何公开的服务来说,这都是必须的,因为密码和授权令牌等敏感信息正在客户机和服务器之间传递。

用户名/密码身份验证

让我们首先看看普通的旧式身份验证是如何工作的。

  • 用户连接到 https://example.com
  • 服务器提供一个富 Javascript 应用程序,该应用程序呈现初始页面。页面中的某个地方有一个登录表单。
  • 由于用户没有登录,这个单页应用程序的许多部分都没有填充数据。所有这些部分在“ login”事件上都有一个事件侦听器。所有这些都是客户端的东西,服务器不知道这些事件。
  • 用户输入他/她的登录名和密码并点击提交按钮,这将触发 Javascript 处理程序在客户端变量中记录用户名和密码。然后这个处理程序触发“ login”事件。同样,这是所有客户端操作,还没有将凭据发送到服务器
  • 调用“ login”事件的侦听器。现在,其中的每一个都需要向 https://example.com/api上的 RESTful API 发送一个或多个请求,以获取要在页面上呈现的用户特定数据。他们发送给 Web 服务的每一个请求都将包含用户名和密码,可能采用 HTTP Basic身份验证的形式,因为 RESTful 服务不允许维护从一个请求到下一个请求的客户端状态。由于 Web 服务处于安全 HTTP 状态,所以在传输过程中密码是安全加密的。
  • 位于 https://example.com/api的 Web 服务接收一组单独的请求,每个请求都带有身份验证信息。根据用户数据库检查每个请求中的用户名和密码,如果发现正确,则执行请求的函数,并以 JSON 格式将数据返回给客户机。如果用户名和密码不匹配,将以401 HTTP 错误代码的形式向客户端发送错误。
  • 不必强迫客户端在每个请求中发送用户名和密码,您可以在 RESTful 服务中使用“ get _ access _ token”函数,该函数接收用户名和密码并用令牌进行响应,令牌是某种加密散列,它是唯一的,并且有一些与之相关的过期日期。这些令牌与每个用户一起存储在数据库中。然后,客户机在后续请求中发送访问令牌。然后将根据数据库而不是用户名和密码验证访问令牌。
  • 像手机应用程序这样的非浏览器客户端应用程序也会做同样的事情,它们要求用户输入他/她的凭证,然后随着每个对 Web 服务的请求发送这些凭证(或者由它们生成的访问令牌)。

从这个例子中可以得出的重要结论是 RESTful Web 服务需要对每个请求进行身份验证

此场景中的另一个安全层将在用户身份验证之外添加客户端应用程序授权。例如,如果你的 web 客户端、 iOS 和 Android 应用程序都在使用 web 服务,你可能希望服务器知道给定请求的三个客户端中的哪一个是客户端,而不管认证用户是谁。这可以使您的 Web 服务将某些功能限制到特定的客户端。为此,您可以使用 API 键和机密,有关这方面的一些想法,请参阅 这个答案

Facebook 认证

上面的工作流程不适用于 Facebook 连接,因为通过 Facebook 登录有第三方,即 Facebook 本身。登录过程要求用户被重定向到 Facebook 的网站,在那里凭证是在我们的控制之外输入的。

那么让我们看看事情是如何变化的: 。

  • 用户连接到 https://example.com
  • 服务器提供一个富 Javascript 应用程序,该应用程序呈现初始页面。在页面中有一个登录表单,其中包括一个“登录 Facebook”按钮。
  • 用户单击“ Login with Facebook”按钮,这只是一个重定向到(例如) https://example.com/auth/facebook的链接。
  • https://example.com/auth/facebook路由由 passport.js 处理(参见 文件)
  • 用户看到的只是页面的变化,现在他们在一个 Facebook 托管页面,他们需要登录和授权我们的网络应用程序。这完全超出了我们的控制范围。
  • 用户登录到 Facebook 并给予我们的应用程序许可,因此 Facebook 现在重定向回到我们在 passport.js 设置中配置的回调 URL,它遵循 文件中的示例是 https://example.com/auth/facebook/callback
  • https://example.com/auth/facebook/callback路由的 passport.js 处理程序将调用回调函数,该函数接收 Facebook 访问令牌和来自 Facebook 的一些用户信息,包括用户的电子邮件地址。
  • 通过电子邮件,我们可以在我们的数据库中定位用户,并将 Facebook 访问令牌与其存储在一起。
  • 在 Facebook 回调中要做的最后一件事是重定向回到富客户机应用程序,但是这一次我们需要将用户名和访问令牌传递给客户机,以便客户机能够使用它们。这可以通过多种方式实现。例如,可以通过服务器端模板引擎将 Javascript 变量添加到页面,或者可以使用此信息返回 cookie。(感谢@RyanKimber 指出在 URL 中传递这些数据的安全问题,正如我最初建议的那样)。
  • 现在我们再次启动单页面应用程序,但是客户机拥有用户名和访问令牌。
  • 客户端应用程序可以立即触发“ login”事件,并让应用程序的不同部分从 Web 服务请求它们需要的信息。
  • 发送到 https://example.com/api的所有请求都将包括用于身份验证的 Facebook 访问令牌,或者应用程序自己的访问令牌通过 REST API 中的“ get _ access _ token”函数从 Facebook 的令牌生成。
  • 非浏览器应用程序在这里有点困难,因为 OAuth 需要一个网络浏览器来登录。要从手机或桌面应用程序登录,你需要启动一个浏览器来重定向到 Facebook,更糟糕的是,你需要一种方法让浏览器通过某种机制将 Facebook 访问令牌传递回应用程序。

我希望这能回答大部分问题。当然,你可以用 Twitter、 Google 或任何其他基于 OAuth 的认证服务来取代 Facebook。

我很想知道有没有更简单的方法。

我非常感谢@Miguel 对每个案例的完整流程的解释,但我想在 Facebook 身份验证部分添加一些内容。

Facebook 提供了一个 Javascript SDK,您可以使用它直接获取客户端的访问令牌,然后将其传递给服务器,用于进一步从 Facebook 获取所有用户信息。所以基本上不需要任何重定向。

此外,您还可以为移动应用程序使用相同的 API 端点。只需使用 Android/iOS SDK for Facebook,在客户端获取 Facebook access _ token 并将其传递给服务器。

关于解释过的 无国籍的本性,当 get _ access _ token 用于生成令牌并传递给客户机时,该令牌也存储在服务器上。所以它和会话令牌一样好,我相信它是有状态的?

只是我的2分钱. 。

下面是我发现的一篇很棒的文章,它可以帮助你验证:

  • 脸书
  • 推特
  • 谷歌
  • 本地认证

轻松节点身份验证: 安装和本地