使用 Facebook iPhone SDK 时如何刷新 oauth 令牌

Posted

技术标签:

【中文标题】使用 Facebook iPhone SDK 时如何刷新 oauth 令牌【英文标题】:how to refresh an oauth token when using the Facebook iPhone SDK 【发布时间】:2011-04-06 08:34:46 【问题描述】:

我在我的应用中使用 ios 版 Facebook SDK:http://github.com/facebook/facebook-ios-sdk

oAuth 令牌在大约 2 小时后过期。我怎样才能“刷新” oAuth 令牌而不必再次调用 [Facebook authorize...] 方法 - 如果用户先前已登录,该方法会短暂显示一个空的 Facebook 对话框?我想避免的是要求用户在每次使用应用程序时重新登录 FB - 比如说,每天。

当应用程序退出/启动时,我已经在保存/恢复 oAuth 令牌。我可以使用 [Facebook isSessionValid] 或通过检查令牌的过期时间来检查令牌是否有效。但是,如果令牌已过期怎么办?我读过可以“刷新”令牌,但我不明白这是如何完成的。

我不想请求“offline_access”权限,这会给我一个“永远”令牌。

帮忙!?

【问题讨论】:

你能找到答案吗? 【参考方案1】:

只要 [[FBSession session] resume] 如果返回 false 就重新登录

【讨论】:

这是我以前做的。 github 上最新的 FB SDK 删除了 FBSession 对象,我在任何地方都看不到“恢复”方法。【参考方案2】:

Facebook iOS SDK 不处理会话存储。 FBSessionDelegate 是您的应用程序应实现的回调接口。它的方法将在应用程序成功登录或注销时被调用。

查看示例应用程序facebook-ios-sdk/sample/DemoApp/Classes/DemoAppViewController.m 以了解fbDidLoginfbDidNotLoginfbDidLogout 方法

【讨论】:

【参考方案3】:

Facebook 的 OAuth 实现不支持令牌刷新。

您在 Facebook 中有 2 种 access_tokens。短期令牌,默认情况下提供,如果您请求离线访问,则提供长期令牌。如果支持刷新令牌,则与为所有应用提供离线访问令牌相同。

只要用户在您的 Web 控件上有一个活动的 facebook 会话,您就可以通过访问 https://www.facebook.com/dialog/oauth?client_id=YOUR_APP_ID&redirect_uri=http://www.facebook.com/connect/login_success.html&response_type=token 或可能执行相同操作的一些 iOS SDK 命令来请求新的 access_token(从未使用过它,所以我不能告诉)。这种请求不会要求用户再次登录,但会使用第一次登录时创建的前一个会话。

【讨论】:

【参考方案4】:

根据 Facebook SDK 文档:

Facebook SDK 会自动刷新用户的会话,如果 必要的。当它这样做时,状态也转换到 FBSessionStateOpenTokenExtended 状态。

还要进一步澄清(自 SDK 3.1 版起):

SDK 会在 API 调用时自动刷新会话。

它还会在使用 SDK 进行后续身份验证或 Facebook API 调用时根据需要刷新令牌数据。

【讨论】:

是的;我的问题已经有几年了。从那时起,FBSDK 已经发展了很多! 正在寻找这个答案并且出现了这个SO线程,所以我总结了我自己研究的内容。【参考方案5】:

由于这些答案都没有真正解决这个问题,我将详细说明我是如何使用 Facebook SDK 实现 OAuth 令牌刷新的。

SDK 会在您发出请求时自动刷新您的令牌,但是在我的场景中,我们将令牌发送到我们的服务器,并且我们需要使用最新的令牌。因此,当我们的服务器指示我们需要新令牌时,我们会这样做:

注意您可以将 AppID 传递给FBSession,也可以将FacebookAppID 键添加到您的应用程序列表中(这就是我们所做的)。

- (void)renewFacebookCredentials 
    if (FBSession.activeSession.state == FBSessionStateOpen ||
        FBSession.activeSession.state == FBSessionStateOpenTokenExtended) 
        [self sessionStateChanged:[FBSession activeSession] state:[FBSession activeSession].state error:nil];
     else 
        // Open a session showing the user the login UI
        // You must ALWAYS ask for public_profile permissions when opening a session
        [FBSession openActiveSessionWithReadPermissions:@[@"public_profile",@"email"]
                                           allowLoginUI:NO
                                      completionHandler:^(FBSession *session, FBSessionState state, NSError *error) 
                                          //this block will run throughout the lifetime of the app.
                                          [self sessionStateChanged:session state:state error:error];
                                      ];
    

您可以使用 Facebook 在其文档中包含的 sessionStateChanged: 方法,但简化的处理程序如下所示:

- (void)sessionStateChanged:(FBSession *)session state:(FBSessionState) state error:(NSError *)error 
    // If the session was opened successfully
    NSString *accessToken;
    if (!error && state == FBSessionStateOpen && [[session accessTokenData] accessToken])
        // Show the user the logged-in UI

        //@see http://***.com/questions/20623728/getting-username-and-profile-picture-from-facebook-ios-7
        accessToken = [[session accessTokenData] accessToken];
       //Now we have an access token, can send this to the server...
     else 
       //No access token, show a dialog or something
    

   //either call a delegate or a completion handler here with the accessToken

请注意,一些 FBSession API 调用会检查线程关联性,因此我发现我必须将所有 FBSession 调用包装在 dispatch_async(dispatch_get_main_queue(), ^...

【讨论】:

【参考方案6】:

从今天开始,Facebook 应该会自动刷新令牌,对 GraphAPI 的请求也可以在不提供令牌字符串的情况下完成(Facebook 会在后台处理它)。

此外,如果碰巧用户长时间未使用应用程序并且他的令牌设法过期,那么在您对 Graph API 的下一次请求时,Facebook 的 SDK 将显示一个警报,要求用户重新登录(所有这些都已处理由 Facebook 完成,完成后 - 将返回 FBSDKGraphRequest 的关闭)。

但是,如果有人真的有理由手动刷新访问令牌,这里有一个示例(Swift 4):

private var selfDestructableNotificationToken: NotificationTokenThatAutomaticallyRemovesObserver?
final class NotificationTokenThatAutomaticallyRemovesObserver: NSObject  // more info here: https://oleb.net/blog/2018/01/notificationcenter-removeobserver/
    let token: Any
    init(_ token: Any)  self.token = token 
    deinit  NotificationCenter.default.removeObserver(token) 


...

if let currentFBToken = FBSDKAccessToken.current()  // if this is a Facebook user, not an email-based user
    if FBSDKAccessToken.currentAccessTokenIsActive()  // and his token has not expired yet
        let token = NotificationCenter.default.addObserver(forName: NSNotification.Name.FBSDKAccessTokenDidChange, object: nil, queue: OperationQueue.main)  notification in
            if let userInfo = notification.userInfo, let refreshedToken = userInfo["FBSDKAccessToken"] as? FBSDKAccessToken 
                self.fbAccessToken = refreshedToken.tokenString
             else 
                self.fbAccessToken = currentFBToken.tokenString // falling back to using an old token (better than none)
            
        
        self.selfDestructableNotificationToken = NotificationTokenThatAutomaticallyRemovesObserver(token)
        FBSDKAccessToken.refreshCurrentAccessToken  _, _, error in
            if let error = error 
                print("failed to refresh Facebook token with error \(error.localizedDescription)")
                self.fbAccessToken = currentFBToken.tokenString // falling back to an old token (better than none)
            
        
     else if FBSDKAccessToken.current().isExpired  // unlucky user. Probably returned to the app after > 2 months break
        self.fbAccessToken = currentFBToken.tokenString // assigning expired token. Facebook will ask user to relogin as soon as we call Graph API with that expired token
    

【讨论】:

以上是关于使用 Facebook iPhone SDK 时如何刷新 oauth 令牌的主要内容,如果未能解决你的问题,请参考以下文章

在 iPhone 应用程序中,如何将照片发布到 Facebook 粉丝页面。在它之前如何喜欢它?使用 facebook-ios-sdk

iPhone ARC 和 Facebook SDK

使用 Facebook iPhone SDK 时如何刷新 oauth 令牌

iphone sdk 的 Facebook 聊天框架

安装 Facebook SDK - iPhone

使用 FB Message Dialog iphone sdk 打开 facebook messenger