使用Facebook进行身份验证的网站的REST API

86

我们有一个网站,唯一的登录和认证方式是使用Facebook(这不是我的选择)。第一次使用Facebook登录时,系统会自动为您创建一个帐户。

现在,我们想为我们的网站创建一个iPhone应用程序,并提供一个公共API供其他人使用我们的服务。

这个问题是关于如何从应用程序/API与我们的网站进行身份验证,可以分为两个部分:

  1. 如果一个网站只使用Facebook OAuth作为身份验证方法,正确的处理REST身份验证的方法是什么?

我已经阅读并研究了很多关于REST API标准身份验证方法的文章。我们不能使用像Basic Auth over HTTPS这样的方法,因为没有用户的凭据。像这样的方法似乎只用于验证使用API的应用程序。

目前,我能想到的最好的方法是在我们的API上访问/authorize终点,它会重定向到Facebook OAuth,然后重定向回网站并提供一个“令牌”,API的用户可以使用它来认证后续请求。

  1. 对于我们创建的官方应用程序,我们不一定需要以相同的方式使用公共API。那么,与我们的网站交互和验证用户的最佳方法是什么?

我理解(我想)如何验证使用我们的API的第三方应用程序,使用API(公共)密钥和密钥(私有)。然而,当涉及到验证使用应用程序的用户时,当我们唯一的身份验证方式是Facebook时,我开始感到非常困惑。

我觉得我可能漏掉了一些非常明显的东西,或者不完全了解公共REST API的工作原理,因此任何建议和帮助都将不胜感激。


我在 https://dev59.com/Y10a5IYBdhLWcg3whJDW 上有一个类似的问题,讨论了其中一些内容。 - JVK
3个回答

100

更新:请见下文

我也在认真考虑这个问题。目前还不是很清楚,但我正在考虑以下路线。我正在创建一个REST API,我的用户仅使用Facebook连接进行身份验证。

在客户端:

  1. 使用Facebook API登录并获取OAUTH2代码。
  2. 交换此代码以获得访问令牌。
  3. 在调用我的自定义API时,我将包括Facebook用户ID和访问令牌。

对于需要用户身份验证的每种方法,在API上执行以下操作:

  1. 使用上面的访问令牌向/me Facebook图形发送请求。
  2. 验证返回的Facebook用户ID是否与上面从我的API传递的用户ID匹配。
  3. 如果访问令牌已过期,则需要进行其他通信。

我还没有测试过。听起来怎么样?

--- 更新:2014年7月27日回答问题 ---

我只在登录一次时使用上述交换。确定登录的用户后,我创建自己的访问令牌,并从那时起使用该令牌。因此,新流程如下...

在客户端:

  1. 使用Facebook API登录并获取OAUTH2代码。
  2. 交换此代码以获得访问令牌。
  3. 在请求我的API的访问令牌时,包括Facebook令牌作为参数

在API上:

  1. 接收访问令牌请求。
  2. 使用Facebook访问令牌向/me Facebook图形发送请求
  3. 验证Facebook用户是否存在并匹配我的数据库中的用户
  4. 创建自己的访问令牌,保存并返回给客户端,从此时起使用。

我认为在服务器上调用/me并生成自己的访问令牌,这将被移动客户端使用是一个不错的选择。 - Der_Meister
我发现将FB密码存储在移动应用中是不好的做法。Facebook建议只将其存储在您自己的服务器上。 https://developers.facebook.com/docs/opengraph/using-actions/#appaccesstoken - Der_Meister
如果我们每次将user_id和access_token作为post/get参数发送到API服务器,那么如果有人能够拦截连接,这会创建安全漏洞吗? - Nathan Do
@Johny19 Facebook会响应我指定的URL并返回访问令牌。然后服务器从查询字符串中获取令牌。我确保将其交换为更持久的令牌,然后将其保存在数据库中。然后,我使用Facebook的PHP SDK调用Facebook图形的“/me”路由。我不熟悉在原生应用程序上使用Facebook的SDK,但我相信一旦您获得访问令牌,他们的iOS / Android SDK将允许您进行调用。 - Chris Greenwood
我也遇到了同样的问题,而且很喜欢你目前提出的解决方案(我刚刚看到它),但是我想知道它如何适用于第三方客户端?我是否正确地认为它的工作方式相同?第三方请求从fb获取访问令牌,将其传递给您自己的API,进行验证并向第三方客户端提供API访问令牌以进行进一步的请求。那么这样安全吗?我真的需要监控哪些第三方客户端被允许使用我的API,并仅使用可信任的客户端吗? - PSR
显示剩余12条评论

15

这是我使用JWT(JSON Web Tokens)的实现,基本上与Chris的更新答案类似。我使用了Facebook JS SDK和JWT。

下面是我的实现步骤:

  1. 客户端:使用Facebook JS SDK登录并获取访问令牌(access token)。

  2. 客户端:通过调用/verify-access-token端点向我的API请求JWT。

  3. 我的API:接收访问令牌,并通过调用Facebook API的/me端点进行验证。

  4. 我的API:如果访问令牌有效,则从数据库中查找用户,如果存在则登录用户。创建一个JWT,将所需字段作为负载,设置到期时间,用秘钥签名并发送回客户端。

  5. 客户端:将JWT存储在本地存储中。

  6. 客户端:随着对下一个API调用请求,发送令牌(第5步中的JWT)。

  7. 我的API:使用密钥验证令牌,如果令牌有效,交换令牌以获得新令牌,并将其与API响应一起发送回客户端。(此后没有验证令牌的外部API调用)[如果令牌无效/过期,则要求客户端重新进行身份验证并从第1步重复]

  8. 客户端:使用新令牌替换存储的令牌,并将其用于下一个API调用。一旦令牌到期,它将失效,从而撤销对API的访问。

每个令牌只能使用一次。

阅读更多关于安全和JWT的答案

JWT有多安全

如果您可以解码JWT,那么它们如何安全?

将JSON Web Tokens(JWT)用作用户标识和认证令牌


3
我猜想#3应该是/debug_token,这样你就可以检查令牌是否真的属于你的应用程序。 - Peppe L-G
2
不要在客户端中请求 access_token。使用“代码工作流”。将 code 传递给 MyAPI,并与 Facebook 进行另一次往返以交换 codeaccess_token。这里有更详细的解释:https://developers.facebook.com/docs/facebook-login/security - omikron

5
我正在尝试回答相同的问题,并最近进行了大量阅读... 我没有“确切的”答案,但对我来说事情变得更加清晰了。你读过你提到的文章中的评论吗?我觉得它们非常有趣和有用。
因此,鉴于自第一篇文章以来事情的发展,这是我认为我会做的:
  • 全站启用HTTPS — 这样您就可以忘记HMAC、签名、nonce等等。

  • 使用OAuth2:

    • 当身份验证请求来自我自己的应用程序/网站时,使用之前提到的回复文章中描述的这个"技巧"(或它的变形)。

    • 在我的情况下,我有两种类型的用户:那些具有传统登录/密码凭据的用户和那些使用Facebook Connect注册的用户。
      所以我会提供一个常规的登录表单,带有"使用Facebook登录"按钮。如果用户使用他的"经典"凭证登录,我会将这些凭证发送到我的OAuth2终点,并带有grant_type=password
      如果他选择通过Facebook登录,我认为这将是一个两步过程:

      • 首先,使用Facebook iOS SDK打开一个FBSession。
      • 当完成这个操作并且应用程序被返回控制权时,应该有一种方法来获取该用户的Facebook ID。我会仅将此ID发送到我的OAuth2终点,并使用由我的服务器理解的扩展授权,表示"使用FB用户ID"。
请注意,我仍在深入研究所有这些内容,因此可能不是完美的答案...甚至可能不正确!但我认为这将是一个很好的起点。使用“扩展授权”来进行Facebook身份验证的想法可能涉及到注册以正确执行某些操作?我不太确定。
无论如何,我希望我能帮助你一点,并且至少可以开始讨论找到解决这个问题的最佳方法 :)
更新 正如评论中指出的那样,Facebook登录不是一个解决方案:任何人都可以发送任意用户ID并作为该用户登录API。
那么像这样做怎么样:
  • 显示一个带“Facebook登录”按钮的登录表单
  • 如果选择此登录方式,则要像Facebook SDK一样操作:打开来自身份验证服务器的网页,该网页将启动Facebook登录。
  • 用户登录后,Facebook将使用您的重定向URL进行确认;使该URL指向您的身份验证服务器的另一个终端点(可能带有额外的参数,指示该调用来自应用程序?)
  • 当命中身份验证终端点时,身份验证可以安全地识别用户,保留其FB用户ID / FB会话,并使用自定义URL方案向您的应用程序返回访问令牌,就像Facebook SDK一样执行

看起来更好了吗?


1
谢谢您的回复!我已经考虑了您所说的大部分内容,但是我对使用FB iOS SDK并发送Facebook用户ID的主要担忧是,是否很容易将任何想要发送的ID发送到API端点并声称自己是另一个用户?这就是我通常会陷入困境的地方... - Adam
确实!我太蠢了,没有想到那个…… 所以解决方案必须通过您自己的身份验证服务器进行处理…… - Olivier Lance
我已经更新了我的答案,并提出了另一个解决方案的想法...但是我刚刚意识到你在原始问题中已经提到了它!目前我看不到其他东西... - Olivier Lance

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接