14

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

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

我有两个问题:

  • 当我的服务方法被调用并且我从我的数据库中检索适当用户的令牌时,有没有办法知道访问令牌是否过期?
    我已经读过,当执行 Facebook API 调用并且访问令牌过期时,会引发以下异常:OAuthException. 但是有没有更好的方法来检测到期?我不想
    1. 调用 Facebook API
    2. 处理异常
    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 的请求/回调中检索到的新访问令牌,以便稍后继续使用新的访问令牌?
4

3 回答 3

14

我不了解 C# SDK,但所有 facebook SDK 基本上只是对图形不同 url 的 http 请求的包装器。

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

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

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

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

您还可以使用处理无效和过期访问令牌的官方文档。如果 C# SDK 不适合您,那么您可能只想自己实现它,以满足您自己的需要,应该很容易。

于 2012-05-04T15:57:05.273 回答
12

您真的应该将 c#sdk 更新到最新版本 - 随着时间的推移,它们修复了很多问题..

更新令牌
这是我们自己处理更新调用的代码(c#sdk 版本 6.0.16,但这也应该适用于早期版本):

    /// <summary>
    /// Renews the token.. (offline deprecation)
    /// </summary>
    /// <param name="existingToken">The token to renew</param>
    /// <returns>A new token (or the same as existing)</returns>
    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返回剩余的秒数新获得的代币(应该接近 500 万 => 60 天))。

无论如何,我不确定是否有办法从令牌中获取过期时间,而无需再次调用身份验证进程。我知道Facebook 调试器会返回这个,但这并没有真正帮助..

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

于 2012-05-08T16:37:49.573 回答
5

到期时间

简短的回答:你得到几秒钟,直到它过期,但 c# api 似乎没有公开它。

根据this facebook documentation,当您获得令牌时,您将获得令牌到期前的秒数作为参数。该文档将响应格式列为:

access_token=USER_ACESS_TOKEN&expires=NUMBER_OF_SECONDS_UNTIL_TOKEN_EXPIRES 

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

不幸的是,它与此处声明的 C# SDK 文档直接矛盾

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

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

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

所以它有数据,但由于某种原因没有公开它(至少在那里,我没有进一步研究)。我会说要么在图书馆周围挖掘更多,看看它是否暴露在某个地方,在github上分叉并修补它(我相信这是一个单行更改),或者使用反射来读取你自己代码中的私有变量。

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

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

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

有没有办法让服务方法等待我们从

当然,在你处理异常之后。

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

另一种更有效(对于单个服务器)但复杂的方法是让系统获取带有身份验证令牌引发事件的回调,并让重试逻辑监听这些事件。

当您的代码因为令牌过期而出现异常时,请在 catch 块中创建一个将重做请求的函数,然后将其作为事件侦听器添加到 auth 事件中。让函数检查事件是否为请求事件的用户提供新的身份验证令牌,如果是,则发出请求。同样,请记住设置最大重试次数。

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

于 2012-05-03T20:31:17.680 回答