在 iOS 应用中处理多个 Facebook 用户登录

Posted

技术标签:

【中文标题】在 iOS 应用中处理多个 Facebook 用户登录【英文标题】:Handling multiple Facebook user logins in an iOS app 【发布时间】:2013-12-16 21:50:10 【问题描述】:

我有一个可以有多个用户的 ios 应用程序,我想将 Facebook 集成到其中。我想缓存每个用户的登录凭据。用户将有一个应用程序登录,因此每个用户将只能使用自己的 Facebook 凭据。 Facebook 的文档指出,您可以通过在此处覆盖 FBSessionTokenCachingStrategy 对象来管理多个用户的会话令牌:

https://developers.facebook.com/docs/ios/login-tutorial/

我正在使用本地缓存方法,我让它在用户登录我的应用程序时工作,然后如果他们有相关的 Facebook 令牌,我将他们登录到那里的会话中。否则,我会提示他们使用 Facebook 的 API 输入 Facebook 凭据,该 API 将用户重定向到 Facebook 网络登录页面。

[FBSession openActiveSessionWithReadPermissions:@[@"basic_info"]
                                   allowLoginUI:YES
                              completionHandler:
 ^(FBSession *session, FBSessionState state, NSError *error)
 
     [self loginToFacebookEnd:session state:state error:error];
 ];

上述方法非常适合第一个用户。第二个登录的用户按预期重定向到 Facebook 网络登录页面,但第一个用户现在通过 safari 登录,第二个用户现在使用第一个用户的凭据登录。

我希望能够不让用户在 safari 上保持登录状态,或者能够使用嵌入式 Web 对话框之类的东西。然而,根据 Facebook API 文档,嵌入式对话框似乎不允许我在应用重新启动后加载用户令牌:

https://developers.facebook.com/docs/ios/login-tutorial/#control

“嵌入式WebView登录对话框缺点:人家要填 他们每次通过登录流程时的登录凭据。”

此外,当令牌从嵌入式 WebView 保存时,调用以下方法会清除我的令牌缓存:

FBSession *session = [[FBSession alloc] initWithAppID:nil
                                          permissions:@[@"basic_info"]
                                      urlSchemeSuffix:nil
                                   tokenCacheStrategy:tokenCaching];

有谁知道如何支持多个用户从 iOS 应用程序登录 Facebook,而不会将第一个用户的凭据缓存在 Safari 中?

更新 1

好的,我知道现在可以使用 Embedded WebView 处理多个用户,因为 Facebook 包含的 SDK 中的示例程序之一 (SwitchUserSample) 可以做到这一点。加载我的 FBSession 似乎有问题,因为很多值都是空的,尽管我调用的代码与示例完全相同。有谁知道什么会导致会话像这样恢复:

<FBSession: 0x16d9f3a0, state: FBSessionStateCreated, loginHandler: 0x0, appID: 658013034244859, urlSchemeSuffix: , tokenCachingStrategy:<FBSessionTokenCachingStrategy: 0x16d56190>, expirationDate: (null), refreshDate: (null), attemptedRefreshDate: 0001-12-30 00:00:00 +0000, permissions:(null)>

如果我使用 FBSessionLoginBehaviorForcingWebView 以外的任何行为,那么我会将此作为我的反序列化令牌:

<FBSession: 0x155823d0, state: FBSessionStateOpen, loginHandler: 0x73364, appID: 658013034244859, urlSchemeSuffix: , tokenCachingStrategy:<FBSessionTokenCachingStrategy: 0x15577c90>, expirationDate: 2014-02-15 20:01:50 +0000, refreshDate: 2013-12-17 20:01:51 +0000, attemptedRefreshDate: 0001-12-30 00:00:00 +0000, permissions:(
    "user_birthday",
    "user_friends"
)>

更新 2

我已经确定这肯定与我的令牌如何被缓存有关。我已经复制了 Facebook 示例使用的方法,但在 FBSession 中我的日期仍然为空值。以下是我调用的缓存方法:

+ (FBSessionTokenCachingStrategy*)createCachingStrategyForSlot:(int)slot 
    FBSessionTokenCachingStrategy *tokenCachingStrategy = [[FBSessionTokenCachingStrategy alloc]
                                                           initWithUserDefaultTokenInformationKeyName:[NSString stringWithFormat:@"SUUserTokenInfo%d", slot]];
    return tokenCachingStrategy;


+ (FBSession*)createSessionForSlot:(int)slot 
    FBSessionTokenCachingStrategy *tokenCachingStrategy = [self createCachingStrategyForSlot:slot];
    FBSession *session = [[FBSession alloc] initWithAppID:nil
                                              permissions:@[@"basic_info",@"user_birthday"]
                                          urlSchemeSuffix:nil
                                       tokenCacheStrategy:tokenCachingStrategy];
    return session;

我是这样称呼它的:

+ (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI

    BOOL openSessionResult = NO;    
    FBSession *session = [self createSessionForSlot:1];

    // If showing the login UI, or if a cached token is available, then open the session.
    if (allowLoginUI || session.state == FBSessionStateCreatedTokenLoaded)
    
        // For debugging purposes log if cached token was found
        if (session.state == FBSessionStateCreatedTokenLoaded)
        
            NSLog(@"Cached token found.");
        

        // Set the active session
        [FBSession setActiveSession:session];

        // If the session state is not any of the two "open" states when the button is clicked
        if (FBSession.activeSession.state != FBSessionStateOpen && FBSession.activeSession.state != FBSessionStateOpenTokenExtended)
        
            // Open the session.
            [session openWithBehavior:FBSessionLoginBehaviorForcingWebView
                    completionHandler:^(FBSession *session,
                                        FBSessionState state,
                                        NSError *error)
             
                 [SocialInteraction loginToFacebookEnd:session state:state error:error];
             ];
        

        // Return the result - will be set to open immediately from the session
        // open call if a cached token was previously found.
        openSessionResult = session.isOpen;
    
    return openSessionResult;

令人沮丧的是,如果我将登录行为从 FBSessionLoginBehaviorForcingWebView 更改为 FBSessionLoginBehaviorWithFallbackToWebView,那么令牌会正确加载!但是,这种行为不适用于我的应用程序。我必须缺少其他一些设置,可以让嵌入式 WebView 缓存其令牌。

【问题讨论】:

如果您的 FBSession 实例的状态是 FBSessionStateCreated,那么您将没有 expireDate 属性等。根据我的经验,它必须有效地打开(FBSessionStateCreatedTokenLoaded、FBSessionStateOpen 或令牌扩展一个 - 忘了什么它现在被调用)。您的 FBSession 对象是否有与之关联的 accessToken?如果是,则继续尝试打开会话并查看状态是否发生变化,并且您会获得以前为 NULL 的值。 状态似乎停留在 FBSessionStateCreated 状态,即使在我尝试打开会话之后也是如此。 当您查询 FBSession 实例的访问令牌时 - 您是否能够取回有效的访问令牌? 当我反序列化令牌时,它仅在由 FBSessionLoginBehaviorForcingWebView 以外的行为设置时才有效。我已经更新了上面的 cmets 以包含反序列化的具有不同行为的令牌的样子。 我在我的答案中添加了一种解决方法 - 如果这可行,请告诉我。如果您需要使用网络视图解决方案,我认为如果您能够共享它,直接调试您的项目会更容易吗?随意删除 FB 应用程序 ID(可以使用我自己的)。 【参考方案1】:

我将把这个从评论移到答案,以便我可以输入更多内容:

如果您的FBSession 实例的状态是FBSessionStateCreated,那么您将没有expirationDate 属性等。根据我的经验,它必须有效地打开(FBSessionStateCreatedTokenLoadedFBSessionStateOpenFBSessionStateOpenTokenExtended )。您的 FBSession 对象是否有与之关联的 accessToken?如果是,则继续尝试打开会话并查看状态是否发生变化,并且您会获得以前为 NULL 的值。

当我有一个有效的accessToken时打开FBSession我通常使用:

[FBSession openActiveSessionWithAllowLoginUI:NO];

更新 1:

好的,这是 Web 视图的一种解决方法 - 如果您使用 Safari,则可以使用以下代码清除用户的 cookie。我可能会在 cookie 的域中搜索 Facebook.comfb.com(可能需要对 FB cookie 域进行一些测试):

NSHTTPCookie *cookie;
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (cookie in [storage cookies]) 
    [storage deleteCookie:cookie];

[[NSUserDefaults standardUserDefaults] synchronize];

【讨论】:

嗯...这是一个有趣的想法!我会检查一下。

以上是关于在 iOS 应用中处理多个 Facebook 用户登录的主要内容,如果未能解决你的问题,请参考以下文章

在 ios 中处理多设备/多用户登录的推送通知

多个 ios 应用程序共享一个 facebook 应用程序

从 iOS 应用程序链接到用户的 Facebook 墙

如何在 iOS 应用中及时登录 Facebook

如何在 IOS5 模拟器上获取 Facebook 应用程序?

跨多个应用共享 Facebook 应用 ID