【问题标题】:how to refresh an oauth token when using the Facebook iPhone SDK使用 Facebook iPhone SDK 时如何刷新 oauth 令牌
【发布时间】: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”权限,这会给我一个“永远”令牌。

帮忙!?

【问题讨论】:

  • 你能找到答案吗?

标签: iphone facebook oauth ios


【解决方案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://stackoverflow.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
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-08-13
          • 1970-01-01
          • 2016-02-03
          • 2016-10-07
          • 2012-04-18
          • 2012-07-11
          • 2017-06-24
          • 1970-01-01
          相关资源
          最近更新 更多