这里有很多问题,即使问题是在Node和passport.js的上下文中提出的,真正的问题更多地是关于工作流,而不是如何使用特定技术。
让我们使用@Keith示例设置,对其进行了一些修改以提高安全性:
- Web服务器位于
https://example.com
提供单页Javascript客户端应用程序
- RESTful Web服务位于
https://example.com/api
为富客户端应用程序提供服务器支持
- 在Node和passport.js中实现的服务器。
- 服务器有一个带有“用户”表的数据库(任何类型)。
- 提供用户名/密码和Facebook Connect作为身份验证选项
- 富客户端使REST请求进入
https://example.com/api
- 可能还有其他客户端(例如电话应用程序)在使用Web服务,
https://example.com/api
但不了解Web服务器https://example.com
。
请注意,我使用的是安全HTTP。我认为这对于公开可用的任何服务都是必须的,因为敏感信息(例如密码和授权令牌)正在客户端和服务器之间传递。
用户名/密码认证
让我们看看普通的旧认证如何首先工作。
- 用户连接到
https://example.com
- 服务器提供了呈现初始页面的丰富Javascript应用程序。页面中有一个登录表单。
- 由于用户未登录,此单页面应用程序的许多部分尚未填充数据。所有这些部分在“ login”事件上都有一个事件侦听器。所有这些都是客户端的东西,服务器不知道这些事件。
- 用户输入他/她的登录名和密码,然后单击“提交”按钮,这将触发Javascript处理程序将用户名和密码记录在客户端变量中。然后,此处理程序触发“登录”事件。同样,这是所有客户端操作,凭据尚未发送到服务器。
- 调用“登录”事件的侦听器。现在,每个这些都需要向RESTful API发送一个或多个请求,
https://example.com/api
以获取要呈现在页面上的用户特定数据。他们发送到Web服务的每个请求都将包含用户名和密码,可能采用HTTP Basic的形式身份验证,因为不允许使用RESTful服务维护从一个请求到下一个请求的客户端状态。由于Web服务是基于安全的HTTP,因此在传输过程中将对密码进行安全加密。
- 的Web服务会
https://example.com/api
收到一堆单独的请求,每个请求都带有身份验证信息。将根据用户数据库检查每个请求中的用户名和密码,如果发现正确,则将执行所请求的函数,并将数据以JSON格式返回给客户端。如果用户名和密码不匹配,则会以401 HTTP错误代码的形式向客户端发送错误。
- 您可以在RESTful服务中使用“ get_access_token”功能来代替用户每次请求发送用户名和密码,该功能接受用户名和密码并以令牌进行响应,令牌是一种独特的加密哈希,具有一定的到期时间与之相关的日期。这些令牌与每个用户一起存储在数据库中。然后,客户端在后续请求中发送访问令牌。然后将针对数据库而不是用户名和密码来验证访问令牌。
- 非浏览器客户端应用程序(例如电话应用程序)的操作与上述相同,它们要求用户输入其凭据,然后将其(或从它们生成的访问令牌)与每个请求一起发送到Web服务。
此示例的重要意义在于,RESTful Web服务需要对每个请求进行身份验证。
在这种情况下,除了用户身份验证之外,安全性的另一层将添加客户端应用程序授权。例如,如果您拥有均使用Web服务的Web客户端,iOS和Android应用程序,则可能希望服务器知道给定请求的客户端是三个客户端中的哪一个,而不管经过身份验证的用户是谁。这可以使您的Web服务将某些功能限制为特定的客户端。为此,您可以使用API密钥和机密,有关此问题的一些想法,请参见此答案。
Facebook认证
上面的工作流程不适用于Facebook连接,因为通过Facebook登录具有第三方,即Facebook本身。登录过程要求将用户重定向到Facebook的网站,在该网站上我们无法控制地输入凭据。
因此,让我们看看情况如何变化:
- 用户连接到
https://example.com
- 服务器提供了呈现初始页面的丰富Javascript应用程序。该页面中有一个登录表单,其中包含“使用Facebook登录”按钮。
- 用户单击“使用Facebook登录”按钮,该按钮只是重定向到(例如)的链接
https://example.com/auth/facebook
。
- 该
https://example.com/auth/facebook
路线由passport.js处理(请参阅文档)
- 用户所看到的只是页面发生了变化,现在他们位于Facebook托管页面中,需要登录和授权我们的Web应用程序。这完全超出了我们的控制范围。
- 用户登录到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中传递此数据的安全性问题)。
- 因此,现在我们再次启动单页应用程序,但是客户端具有用户名和访问令牌。
- 客户端应用程序可以立即触发“登录”事件,并让应用程序的不同部分从Web服务请求他们所需的信息。
- 发送到的所有请求都
https://example.com/api
将包括用于身份验证的Facebook访问令牌,或通过REST API中Facebook的令牌通过“ get_access_token”函数从应用程序自身生成的访问令牌。
- 非浏览器应用程序在这里要困难一些,因为OAuth需要使用网络浏览器登录。要从手机或桌面应用程序登录,您将需要启动浏览器以重定向到Facebook,更糟糕的是,您需要一种让浏览器通过某种机制将Facebook访问令牌传递回应用程序的方法。
我希望这能回答大多数问题。当然,您可以用Twitter,Google或任何其他基于OAuth的身份验证服务替换Facebook。
我很想知道是否有人可以使用更简单的方法来处理此问题。
passport-facebook
。完成工作后,下一步就是开始了解Passport的工作方式以及其存储凭据的方式。将其连接到Restify(请参阅此处以获取您提到的更新版本)将是最后一步之一(或者您可以在Express中实现REST接口)。