简体   繁体   English

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

[英]How to transparently renew the Facebook access token while processing a service method which uses Facebook API calls?

I have a WCF service which runs in IIS 7.5 and VS 2010. This service has some methods which internally use the Facebook C# SDK (version 4.1, not latest) in order to perform some GET and POST from/to Facebook. 我有一个在IIS 7.5和VS 2010中运行的WCF服务。此服务有一些方法在内部使用Facebook C#SDK (版本4.1,而不是最新版本),以便从/向Facebook执行一些GET和POST。 Since Facebook will soon remove the offline_access I have to handle the situation where an access token is expired. 由于Facebook将很快删除 offline_access我必须处理访问令牌过期的情况。

I have understood the way the authentication is performed (in order to get the code and after having the code to get the access token) in order to use the Graph API for getting Facebook information (as presented here ). 我已经了解了执行身份验证的方式(为了获取代码并在获取访问令牌之后),以便使用Graph API获取Facebook信息(如此处所示 )。

I have two questions: 我有两个问题:

  • When my service method is called and I retrieve the token of the appropriate user from my DB, is there a way to know if the access token is expired or not? 调用我的服务方法并从数据库中检索相应用户的令牌时,是否有办法知道访问令牌是否已过期?
    I have read that when a Facebook API call is performed and the access token is expired then the following exception is thrown: OAuthException . 我已经读过 ,当执行Facebook API调用并且访问令牌过期时,会抛出以下异常: OAuthException But is there any better way to detect the expiration? 但有没有更好的方法来检测到期? I don't want to 我不想
    1. Call the Facebook API 调用Facebook API
    2. Handle the exception 处理异常
    3. Renew the access token and finally 最后更新访问令牌
    4. Repeat the initial call with the new access token. 使用新的访问令牌重复初始调用。
  • Is it possible to renew the access token of the user transparently (store it also in the DB) and continue to handle the service method? 是否可以透明地更新用户的访问令牌(也将其存储在数据库中)并继续处理服务方法? In this resource, the important ("Renewing an Access Token") part is missing (declared as [todo]) 资源中,缺少重要的(“更新访问令牌”)部分(声明为[todo])

I would like to achieve the following scheme, in the implementation of the Service Method: 我想在服务方法的实现中实现以下方案:

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( ..... )

--

The process to communicate with the QAuth dialog is asynchronous (a redirect is performed), and the communication with access token url to get the access token this is performed synchronously. QAuth对话通信的过程是异步的(执行重定向),并且与访问令牌url的通信以获取访问令牌,这是同步执行的。

Final Question: 最后的问题:

  • Is there a way the service method to wait for the new access token we retrieve from the request / callback with Facebook in order to continue later with the new access token? 有没有办法让服务方法等待我们从Facebook请求/回调中检索的新访问令牌,以便稍后继续使用新的访问令牌?

I don't know about the C# SDK, but ALL facebook SDKs are basically just wrappers for http request to the graph different urls. 我不知道C#SDK,但所有facebook SDK基本上只是http请求图表不同网址的包装。

If you use the server side authentication flow then you should get a long lived token (about 60 days), and you get the expiration time with it, when it expires you need to re-authenticate the user, there's no way to extend the token. 如果您使用服务器端身份验证流程,那么您应该获得一个长期存在的令牌(大约60天),并且您获得它的到期时间,当它到期时您需要重新验证用户,没有办法扩展令牌。

The client side authentication returns a short lived token (about 2 hours) but you can use the new endpoint facebook provided to replace the "offline_token". 客户端身份验证返回一个短期令牌(大约2小时),但您可以使用提供的新端点 facebook来替换“offline_token”。 You can only use that with still valid access tokens. 您只能将其用于仍然有效的访问令牌。

Also, no matter what, you always get the "expires" time when you get an access token, unless it's an application token which does not have an expiration date. 此外,无论如何,当您获得访问令牌时,您始终会获得“到期”时间,除非它是没有到期日期的应用程序令牌。

In either case, if you get a long lived token you can store it in the database and use it on the server side, but be aware that the token can still get invalidated for a number of reasons. 在任何一种情况下,如果您获得一个长期存在的令牌,您可以将其存储在数据库中并在服务器端使用它,但请注意,由于多种原因令牌仍然无效。

You can also use the official documentation for Handling Invalid and Expired Access Tokens . 您还可以使用处理无效和过期访问令牌的官方文档。 If the C# SDK doesn't work well for you then you might want to just implement it yourself, for your own needs, should be pretty easy. 如果C#SDK不适合您,那么您可能希望自己实现它,为了您自己的需要,应该非常简单。

You should really update the c#sdk to the latest version - they fix a lot of issues over time.. 您应该将c#sdk更新到最新版本 - 它们会随着时间的推移解决很多问题。

Renewing a token 续订令牌
This is our code that handles the renew call itself (c#sdk ver 6.0.16, but this should work on earlier versions as well): 这是我们处理续订调用的代码(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;            
    }

Facebook says that the new token may be the same (but extended expiration) or a completely new one, so you should handle that in your logic if required. Facebook表示新令牌可能是相同的(但延长到期时间)或全新的令牌,因此如果需要,您应该在逻辑中处理它。

According to Facebook, you should call the renew up to once a day. 根据Facebook的说法,你应该每天更新一次。 ( https://developers.facebook.com/roadmap/offline-access-removal/ ) https://developers.facebook.com/roadmap/offline-access-removal/

We keep a time-stamp on when the last 'Facebook update' was done, and if that time is over 24h ago and the user is accessing our application, we go in the background and renew the token. 我们在上次“Facebook更新”完成时保留时间戳,如果该时间超过24小时并且用户正在访问我们的应用程序,我们将在后台进行更新令牌。 (we also update other data, name, email and other things we need) (我们还会更新其他数据,姓名,电子邮件和其他我们需要的东西)

Apparently, it is not calling it up to once a day, but calling it once per token. 显然,它不会每天调用一次,而是每个令牌调用一次。

Facebook will not let you renew a longed-live token. Facebook不会让你续订一个长期存在的令牌。 See 'Scenario 4:' at the offline access removal page 请参阅脱机访问删除页面上的 “方案4:”

To clarify: short-lived tokens come from clients, long-lived tokens come from server-side. 澄清一下:短命代币来自客户,长寿代币来自服务器端。

In short, when a user access your app, use the SDK of the client to get a new short-lived token send it to the server, and extend it with your server to make it a long-lived and store that, so you get 60 days from that point. 简而言之,当用户访问您的应用程序时,使用客户端的SDK获取一个新的短期令牌将其发送到服务器,并使用您的服务器扩展它以使其成为一个长期存储并存储,因此您获得从那时起60天。

Handling the Expired time 处理过期时间
In our current usage, we were not required to keep the track of expire time, as all access starts with a client that checks that, but in the same the code access result.access_token it can access result.expires which returns the number of seconds remaining on that newly acquired token (should be close to 5 mil => 60 days)). 在我们当前的用法中,我们不需要保持到期时间的跟踪,因为所有访问都是从检查它的客户端开始的,但在相同的代码访问结果中result.access_token它可以访问result.expires ,它返回秒数留在新获得的令牌上(应该接近5密尔=> 60天))。

In any case, I am not sure there is a way to get the expire time from a token without making another call to the auth process. 在任何情况下,我都不确定是否有办法从令牌获取到期时间而不再调用auth进程。 I know that the Facebook Debugger returns this, but that does not really helps.. 我知道Facebook调试器会返回这个,但这并没有真正帮助..

Renewing an invalid token 续订无效令牌
This will not work , you will get any of the errors as explained here when trying to renew an expired/invalid token. 这将无效 ,您将在尝试续订过期/无效令牌时获得此处所述的任何错误。
Remember to call the renew before it expires and remember that when you call renew on an expired (or any other kind of invalid) you will get an error and need to handle it (we handle it outside the code I pasted). 请记住在续订到期之前调用续订并记住,当您在过期(或任何其他类型的无效)上调用续订时,您将收到错误并需要处理它(我们在我粘贴的代码之外处理它)。

Time till expire 到期的时间

Short answer: you get the seconds until it expires, but the c# api appears not to expose it. 简短的回答:你得到秒数,直到它过期,但c#api似乎不暴露它。

According to this facebook documentation, you get the the number of seconds until the token expires as a paramater when you get the token. 根据这个 facebook文档,当你获得令牌时,你得到令牌到期时的秒数。 The documentation lists the response format as : 文档将响应格式列为:

access_token=USER_ACESS_TOKEN&expires=NUMBER_OF_SECONDS_UNTIL_TOKEN_EXPIRES 

This is backed up by the the draft RFC for Ouath 2 which says responses should contain the expire time. 这得到了Ouath 2的RFC草案的支持,该草案称响应应该包含到期时间。

Unfortunately, it is directly contradicted by the C# SDK documentation that states here that 不幸的是,它与此处所述的C#SDK文档直接相矛盾

There is no way to determine if an access token is expired without making a request to Facebook. 如果没有向Facebook发出请求,则无法确定访问令牌是否过期。 For this reason, you must always assume that an access token could be expired when making requests to Facebook. 因此,您必须始终假设在向Facebook发出请求时,访问令牌可能已过期。

This is not true. 这不是真的。 If you look at the c# SDK source, the object the sdk creates for the OAuth response explicitly contains ( unfortunately as a private variable) the following code 如果查看c#SDK源代码,sdk为OAuth响应创建的对象显式包含(不幸的是作为私有变量)以下代码

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

So it has the data, but for some reason does not expose it ( at least there, I didn't look to much further). 所以它有数据,但由于某种原因不暴露它(至少在那里,我没有进一步看)。 I'd say either dig around the library more and see if its exposed somewhere, fork and patch it on github(i believe it's a one line change), or use reflection to read the private variable in your own code. 我要说要么更多地挖掘库,看看它是否暴露在某个地方,在github上分叉和修补它(我相信这是一行更改),或者使用反射来读取你自己代码中的私有变量。

Continuing to handle the service method and renew token 继续处理服务方法并更新令牌

Short answer: Maybe. 简短的回答:也许吧。 If you knew the token was expired, you could obviosuly get a new one before the request. 如果您知道令牌已过期,您可以在请求之前明显地获得新令牌。

If you don't, than you kinda can, but you need to handle your request failing. 如果你没有,那么你可以,但你需要处理你的请求失败。 In theory, this doesn't mean you need to handle an exception, just look at the http status code (which will be one in the 400s probably 403 forbidden ) however C#'s webrequest method interpets non 200 status c as events that raise an exception. 从理论上讲,这并不意味着您需要处理异常,只需查看http状态代码(400个中的一个可能是403禁止)但是C#的webrequest方法将非200状态c作为引发异常的事件进行处理。 Since the API uses this mechanism to make calls, you only get an exception when they fail. 由于API使用此机制进行调用,因此只有在失败时才会出现异常。

Is there a way for the service method to wait for the new access token we retrieve from the 有没有办法使服务方法等待我们从中检索的新访问令牌

Sure, after you handle the exception. 当然,在你处理异常之后。

Once this happens, asynchronously, you will get a new auth token. 一旦发生这种情况,异步,您将获得一个新的身份验证令牌。 So you can, after catching the exception, wait some amount of time,check if you get a new token for that user, and if so retry . 因此,您可以在捕获异常后等待一段时间,检查是否为该用户获取了新令牌,如果是,则重试。 If keep waiting and checking. 如果继续等待和检查。 Make sure you have a maximum number of retries and a maximum amount of time to wait. 确保您有最大重试次数和最长等待时间。 Pulling the database to check for changes is a little inefficient, so you probably want to pick the time interval you check for changes on carefully and potentially make it exponentially back off . 拉动数据库以检查更改是有点低效的,因此您可能希望选择仔细检查更改的时间间隔,并可能使其以指数方式退回

The other, more efficient (for a single server), but complex way, is to have the system that gets the callback with the auth token raise events and have the retry logic listen for those events. 另一个更有效的(对于单个服务器),但是复杂的方式是让系统通过auth令牌获取回调引发事件并让重试逻辑监听这些事件。

When your code gets an exception because your token is expired, in the catch block make a function that will redo the request and then add it as an event listener to the auth events. 当您的代码因令牌过期而获得异常时,在catch块中创建一个函数,该函数将重做请求,然后将其作为事件侦听器添加到auth事件中。 Have the function check that the event was for a fresh auth token for the users who request the event and if so, make the request. 让函数检查事件是否为请求事件的用户提供了新的身份验证令牌,如果是,请发出请求。 Again, remember to have a maximum retry count. 再次,记住要有最大重试次数。

It is not possible to actually use async/await or something like that to wait for your request for a new token to cmplete. 实际上不可能使用async / await或类似的东西等待您的新令牌的请求完成。 The problem, refreshing the API token is not request that you can wait on the response for , its actually triggering something that eventually causes a seperate get request to be made 问题是,刷新API令牌并不是您可以等待响应的请求,它实际上会触发最终导致单独获取请求的内容
Facebook API请求 Note, although the above diagram is for when a user first logs in, the same sequence happens roughly on a failed call, but it starts with the redirect. 请注意,尽管上图是针对用户首次登录时的情况,但大致在失败的呼叫中会发生相同的序列,但它会从重定向开始。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM