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

14 c# security facebook token facebook-c#-sdk

我有一个在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( ..... )

--
Run Code Online (Sandbox Code Playgroud)

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

最后的问题:

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

Nit*_*mer 14

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

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

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

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

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

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


Jon*_*son 12

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

更新令牌
这是我们处理续订调用的代码(c#sdk ver 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;            
    }
Run Code Online (Sandbox Code Playgroud)

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调试器会返回这个,但这并没有真正帮助..

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


imi*_*ers 5

到期的时间

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

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

access_token=USER_ACESS_TOKEN&expires=NUMBER_OF_SECONDS_UNTIL_TOKEN_EXPIRES 
Run Code Online (Sandbox Code Playgroud)

这得到了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;
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

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

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

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

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

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