应该如何在服务器端使用Facebook用户访问令牌?

前言

我正在开发几个Web服务和一些客户端(Web应用程序,手机等),这些客户端将通过HTTP与所述服务进行接口。 我目前的工作是为产品devise一个authentication和授权解决scheme。 我已决定利用Facebook,Google,Microsoft,Twitter等外部身份提供商进行身份validation。

我试图解决这个问题,“当请求到达我的服务器时,我怎么知道用户是谁,我怎么能确定?”。 下面还有更多的问题

要求

  1. 依靠外部身份来表明我正在处理的是谁(“userId”本质上就是我所关心的)。
  2. 系统应该使用基于令牌的authentication(而不是cookie,例如基本authentication)。

    我相信这是跨多个客户端和服务器进行扩展,同时提供松散耦合的正确select。

工作stream程

基于我对基于令牌的身份validation的阅读和理解,以下是我如何想象工作stream程。 现在让我们在网页浏览器上关注Facebook 。 我的假设是,其他外部身份提供者应该有类似的能力,虽然我还没有确认。

请注意,截至撰写时,我将基于Facebooklogin版本2.2以下

  1. 客户端:使用JavaScript SDK启动Facebook的login
  2. Facebook:用户authentication和批准应用程序权限(例如访问用户的公开个人资料)
  3. Facebook:向包含用户的访问令牌,ID和签名请求的客户端发送响应
  4. 客户端:在浏览器会话中存储用户访问令牌( 方便地由SDK处理 )
  5. 客户端:通过在授权标头中发送用户的访问令牌+用户的标识(潜在地在自定义标头中)向我的Web服务请求安全资源,
  6. 服务器:从请求头读取用户访问令牌,并通过向Facebook提供的debug_tokengraphicsAPI发送请求来启动validation
  7. Facebook:使用用户访问令牌信息(包含appId和userId)回应服务器
  8. 服务器:通过比较appId与预期(本身已知)和userId与客户端请求上发送的内容的比较来完成令牌的validation
  9. 服务器:用请求的资源响应客户端(假定愉快的授权path)

我想象的步骤5-9将重复随后的请求到服务器(而用户的访问令牌是有效的 – 没有过期,从FB侧撤销,应用程序权限改变等)

以下是帮助您完成步骤的图表。 请理解这个系统不是一个单一的页面应用程序(SPA)。 提到的Web服务是API端点,将JSON数据本质上提供给客户端; 他们不提供HTML / JS / CSS(除了Web客户端服务器)。

工作流程图

问题

  1. 首先,根据我的序言和要求,有没有明显的差距/陷阱?

  2. 正在执行一个出站请求到Facebookvalidation访问令牌(上面的步骤6-8) 每客户端请求 /推荐?

    我至less知道,我必须validation来自客户端请求的访问令牌。 但是,第一个后续validation的推荐方法对我来说是未知的。 如果有典型的模式,我有兴趣听到它们。 根据我的要求,我明白他们可能是依赖于应用程序; 然而,我只是不知道该找什么。 一旦我有一个基本的想法,我会尽职尽责。

    例如,可能的想法:

    • 首次validation完成后,将访问令牌+ userId对散列,并将其存储在分布式caching中(所有Web服务器均可访问),并且有效期等于访问令牌。 在随后来自客户端的请求中,对访问令牌+用户ID对进行散列并检查其在caching中的存在。 如果存在,则请求被授权。 否则,请联系FacebookgraphicsAPI以确认访问令牌。 我假设这个策略可能是可行的,如果我使用HTTPS(我会)。 但是,性能如何比较呢?

    • 在此StackOverflow问题中接受的答案build议在Facebook用户令牌的第一次validation完成后创build自定义访问令牌。 自定义标记然后将被发送到客户端为后续的请求。 我想知道这是否比上面的解决scheme更复杂,但是。 这将需要实现我自己的身份提供者(我想避免的,因为我想首先使用外部身份提供者…)。 这个build议有什么价值吗?

  3. 在上面的步骤3中提到的signedRequest字段是否存在( 这里提到),相当于'游戏canvaslogin'stream程中的签名请求参数?

    由于前者在文件中与后者联系起来,似乎被暗示为等同。 不过,我很惊讶在网页文档的“手动构buildloginstream程” 页面中没有提到游戏页面上提到的validation策略。

  4. 如果#3的答案是“是”,那么解码签名的相同身份确认策略和服务器端可能使用的身份确认策略是否相同?

    解码和比较FB文档

    我想知道是否可以利用这一点,而不是像以上build议的那样对debug_tokengraphicsAPI(上面的步骤#6)进行出站调用以确认访问令牌:

    来自FB文档的debug_token图形API

    当然,为了在服务器端进行比较,签名的请求部分将需要与请求一起发送到服务器(上述步骤#5)。 除了可行性而不牺牲安全性之外,我想知道如何将性能与进行出站呼叫进行比较。

  5. 当我在这里,在什么情况/为了什么目的,你会坚持一个用户的访问令牌数据库例如? 我没有看到我需要这样做的场景,但是,我可能忽略了一些东西。 我很好奇,一些常见的情况可能会引发一些想法。

谢谢!

从你所描述的,我build议使用服务器端loginstream程中所述

所以令牌已经在你的服务器上,并且不需要从客户端传递。 如果你使用非encryption连接,这可能是一个安全风险(例如,中间人攻击)。

步骤是:

(1)login人员

您需要在scope参数中指定要从用户收集的权限。 该请求可以通过正常的链接触发:

 GET https://www.facebook.com/dialog/oauth? client_id={app-id} &redirect_uri={redirect-uri} &response_type=code &scope={permission_list} 

看到

(2)确认身份

 GET https://graph.facebook.com/oauth/access_token? client_id={app-id} &redirect_uri={redirect-uri} &client_secret={app-secret} &code={code-parameter} 

(3)检查访问令牌

你可以像你已经在你的问题中所说的那样检查令牌

 GET /debug_token?input_token={token-to-inspect} &access_token={app-token-or-admin-token} 

这只能在服务器端完成,否则你会让你的应用程序访问令牌对最终用户可见(不是一个好主意!)。

看到

(4)扩展访问令牌

一旦你得到(短命)的令牌,你可以做一个调用来扩展令牌的描述

如下所示:

 GET /oauth/access_token?grant_type=fb_exchange_token &client_id={app-id} &client_secret={app-secret} &fb_exchange_token={short-lived-token} 

(5)存取令牌

关于在服务器上存储令牌,FBbuild议这样做:

(6)处理过期的访问令牌

由于FB不会在令牌过期的情况下通知您(如果您未保存到期date并在拨打电话之前将其与当前时间戳进行比较),如果令牌无效,则可能会收到来自FB的错误消息(最多60天后)。 错误代码将是190

 { "error": { "message": "Error validating access token: Session has expired at unix time SOME_TIME. The current unix time is SOME_TIME.", "type": "OAuthException", "code": 190 } } 

看到

如果访问令牌失效,解决办法是让该人员再次login,届时您将能够代表他们再次进行API调用。 您的应用程序用于新人的loginstream程应确定您需要采用哪种方法。