如何在处理使用Facebook API调用的服务方法时透明地更新Facebook访问令牌?

我有一个在IIS 7.5和VS 2010中运行的WCF服务。此服务有一些方法在内部使用Facebook C#SDK (版本4.1,而不是最新版本),以便从/向Facebook执行一些GET和POST。 由于Facebook将很快删除 offline_access我必须处理访问令牌过期的情况。

我已经理解了执行身份validation的方式(为了获取代码并在获取访问令牌之后),以便使用Graph API获取Facebook信息(如此处所示 )。

我有两个问题:

  • 调用我的服务方法并从我的数据库中检索相应用户的令牌时,有没有办法知道访问令牌是否已过期?
    我已经读过 ,当执行Facebook API调用并且访问令牌过期时,会抛出以下exception: OAuthException 。 但有没有更好的方法来检测到期? 我不想
    1. 调用Facebook API
    2. 处理exception
    3. 最后更新访问令牌
    4. 使用新的访问令牌重复初始调用。
  • 是否可以透明地更新用户的访问令牌(将其存储在数据库中)并继续处理服务方法? 在此资源中,缺少重要的(“更新访问令牌”)部分(声明为[todo])

我想在服务方法的实现中实现以下方案:

 sc = SocialNetworkAccountDao.GetByUser(user) isExpired = call method to check if the sc.token is expired. if (isExpired) { newToken = call method for getting new access token sc.token = newToken; SocialNetworkAccount.Update(sc); } Facebook = new Facebook (sc.token) Facebook.Post( ..... ) -- 

QAuth对话通信的过程是异步的(执行重定向),并且与访问令牌url的通信以获取访问令牌,这是同步执行的。

最后的问题:

  • 有没有办法让服务方法等待我们从Facebook请求/回调中检索的新访问令牌,以便稍后继续使用新的访问令牌?

我不知道C#SDK,但所有facebook SDK基本上只是http请求到图表不同url的包装。

如果您使用服务器端身份validation流程,那么您应该获得一个长期存在的令牌(大约60天),并且您获得它的到期时间,当它到期时您需要重新validation用户,没有办法扩展令牌。

客户端身份validation返回一个短期令牌(大约2小时),但您可以使用提供的新端点 facebook来替换“offline_token”。 您只能使用仍然有效的访问令牌。

此外,无论如何,当您获得访问令牌时,您始终会获得“过期”时间,除非它是没有过期日期的应用程序令牌。

在任何一种情况下,如果您获得一个长期存在的令牌,您可以将其存储在数据库中并在服务器端使用它,但请注意,由于多种原因令牌仍然无效。

您还可以使用处理无效和过期访问令牌的官方文档。 如果C#SDK不适合您,那么您可能希望自己实现它,为了您自己的需要,应该非常简单。

您应该将c#sdk更新到最新版本 – 它们会随着时间的推移解决很多问题。

续订令牌
这是我们处理续订调用的代码(c#sdk ver 6.0.16,但这也适用于早期版本):

  ///  /// Renews the token.. (offline deprecation) ///  /// The token to renew /// A new token (or the same as existing) public static string RenewToken(string existingToken) { var fb = new FacebookClient(); dynamic result = fb.Get("oauth/access_token", new { client_id = FACEBOOK_APP_ID, client_secret = FACEBOOK_APP_SECRET, grant_type = "fb_exchange_token", fb_exchange_token = existingToken }); return result.access_token; } 

Facebook表示新令牌可能是相同的(但延长的到期时间)或全新的令牌,因此如果需要,您应该在逻辑中处理它。

根据Facebook的说法,你应该每天更新一次。 ( https://developers.facebook.com/roadmap/offline-access-removal/

我们在上次“Facebook更新”完成时保留时间戳,如果该时间超过24小时并且用户正在访问我们的应用程序,我们将在后台进行更新令牌。 (我们还会更新其他数据,姓名,电子邮件和其他我们需要的东西)

显然,它不会每天调用一次,而是每个令牌调用一次。

Facebook不会让你续订一个长期存在的令牌。 请参阅脱机访问删除页面上的 “方案4:”

澄清一下:短命令牌来自客户端,长寿命令牌来自服务器端。

简而言之,当用户访问您的应用程序时,使用客户端的SDK获取一个新的短期令牌将其发送到服务器,并将其与您的服务器一起扩展,使其成为一个长期存储并存储,因此您获得从那时起60天。

处理过期时间
在我们当前的用法中,我们不需要保持到期时间的跟踪,因为所有访问都是从检查它的客户端开始的,但在相同的代码访问结果中result.access_token它可以访问result.expires ,它返回秒数留在新获得的令牌上(应该接近5密尔=> 60天))。

在任何情况下,我都不确定是否有办法从令牌获取到期时间而不再调用auth进程。 我知道Facebook调试器会返回这个,但这并没有真正帮助..

续订无效令牌
这不起作用 ,在尝试续订过期/无效令牌时,您将获得此处所述的任何错误。
请记住在续订到期之前调用续订并记住,当您在过期(或任何其他类型的无效)上调用续订时,您将收到错误并需要处理它(我们在我粘贴的代码之外处理它)。

到期的时间

简短的回答:你得到秒数,直到它过期,但c#api似乎不暴露它。

根据这个 facebook文档,当你获得令牌时,你得到令牌到期时的秒数作为参数。 文档将响应格式列为:

 access_token=USER_ACESS_TOKEN&expires=NUMBER_OF_SECONDS_UNTIL_TOKEN_EXPIRES 

这得到了Ouath 2的RFC草案的支持,该草案称响应应该包含到期时间。

不幸的是,它与此处所述的C#SDK文档直接相矛盾

如果没有向Facebook发出请求,则无法确定访问令牌是否过期。 因此,您必须始终假设在向Facebook发出请求时,访问令牌可能已过期。

这不是真的。 如果查看c#SDK源代码,sdk为OAuth响应创建的对象显式包含(不幸的是作为私有变量)以下代码

  ///  /// Date and Time when the access token expires. ///  private readonly DateTime _expires; 

所以它有数据,但由于某种原因不暴露它(至少在那里,我没有进一步看)。 我要么说要么更多地挖掘库,看看它是否暴露在某个地方,在github上分叉和修补它(我相信它是一行更改),或者使用reflection来读取你自己代码中的私有变量。

继续处理服务方法并更新令牌

简短回答:也许吧。 如果您知道令牌已过期,您可以在请求之前明显地获得新令牌。

如果你没有,那么你可以,但你需要处理你的请求失败。 从理论上讲,这并不意味着您需要处理exception,只需查看http状态代码(400个中的一个可能是403禁止的)但是C#的webrequest方法将非200状态c作为引发exception的事件进行交互。 由于API使用此机制进行调用,因此只有在失败时才会出现exception。

有没有办法使服务方法等待我们从中检索的新访问令牌

当然,在你处理exception之后。

一旦发生这种情况,异步,您将获得一个新的身份validation令牌。 因此,您可以在捕获exception后等待一段时间,检查是否为该用户获取了新令牌,如果是,则重试。 如果继续等待和检查。 确保您有最大重试次数和最长等待时间。 拉动数据库以检查更改是有点低效的,因此您可能希望选择仔细检查更改的时间间隔,并可能使其以指数方式退回 。

另一个更有效(对于单个服务器),但复杂的方式是让系统通过auth令牌获取回调引发事件并让重试逻辑侦听这些事件。

当您的代码因令牌过期而获得exception时,在catch块中创建一个函数,该函数将重做请求,然后将其作为事件侦听器添加到auth事件中。 让函数检查事件是否为请求事件的用户提供新的身份validation令牌,如果是,请发出请求。 再次,记住要有最大重试次数。

实际上不可能使用async / await或类似的东西等待您的新令牌的请求完成。 问题是,刷新API令牌不是请求您可以等待响应,它实际上触发了最终导致单独获取请求的内容
Facebook API请求 请注意,虽然上图是针对用户首次登录时的情况,但是在失败的呼叫中大致会发生相同的序列,但它会从重定向开始。