使用 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
以了解fbDidLogin
、fbDidNotLogin
和fbDidLogout
方法
【讨论】:
【参考方案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