【问题标题】:Open an FBSession with Existing Token Data on iOS在 iOS 上使用现有令牌数据打开 FBSession
【发布时间】:2013-07-26 13:46:48
【问题描述】:

我有一个后端服务,它将让我登录我的应用程序,并从以前的登录中返回一个扩展的 facebook 令牌,可能来自另一台设备(因此在此设备上没有缓存任何凭据)。我想使用这个令牌来启动 Facebook 会话。我正在使用类似的东西:

FBSession* session = [[FBSession alloc] initWithPermissions:@[@"publish_actions"]];
FBAccessTokenData* tokenData = 
[FBAccessTokenData createTokenFromString:token
                             permissions:@[@"publish_actions"]
                          expirationDate:nil
                               loginType:FBSessionLoginTypeTestUser
                             refreshDate:nil];


[session openFromAccessTokenData:tokenData completionHandler:nil];

为了清楚起见,我在这里传递“nil”,在我的代码中,我正在处理完成并登录返回的会话对象,该对象似乎处于打开状态,没有错误。当我尝试使用会话时,出现如下错误:

Error Domain=com.facebook.sdk Code=5 "The operation couldn’t be completed. (com.facebook.sdk error 5.)" UserInfo=0xb8b1680 {com.facebook.sdk:HTTPStatusCode=403, com.facebook.sdk:ParsedJSONResponseKey={
    body =     {
        error =         {
            code = 200;
            message = "(#200) The user hasn't authorized the application to perform this action";
            type = OAuthException;
        };
    };
    code = 403;
}, com.facebook.sdk:ErrorSessionKey=<FBSession: 0xa2b62a0, state: FBSessionStateOpen, loginHandler: 0xa29e9b0, appID: 131721883664256, urlSchemeSuffix: , tokenCachingStrategy:<FBSessionTokenCachingStrategy: 0xa273f60>, expirationDate: 4001-01-01 00:00:00 +0000, refreshDate: 2013-07-26 16:21:10 +0000, attemptedRefreshDate: 0001-12-30 00:00:00 +0000, permissions:(
    email,
    "publish_actions"
)>}

有什么建议吗...?

【问题讨论】:

  • 这种方法在 sdk 版本 3.21.1 中运行良好。令牌可能不是从 FBSessionLoginTypeTestUser 生成的,这就是为什么它说用户没有被授权。

标签: ios facebook facebook-ios-sdk


【解决方案1】:

我找到了解决方案:(前提是你有一个现有的令牌)

首先将 FBSessionTokenCachingStrategy 类子类化为 MySessionTokenCachingStrategy 并覆盖下面的方法:

- (FBAccessTokenData *)fetchFBAccessTokenData 
{
    NSMutableDictionary *tokenInformationDictionary = [NSMutableDictionary new];

    // Expiration date
    tokenInformationDictionary[@"com.facebook.sdk:TokenInformationExpirationDateKey"] = [NSDate dateWithTimeIntervalSinceNow: 3600];

    // Refresh date
    tokenInformationDictionary[@"com.facebook.sdk:TokenInformationRefreshDateKey"] = [NSDate date];

    // Token key
    tokenInformationDictionary[@"com.facebook.sdk:TokenInformationTokenKey"] = self.token;

    // Permissions
    tokenInformationDictionary[@"com.facebook.sdk:TokenInformationPermissionsKey"] = self.permissions;

    // Login key
    tokenInformationDictionary[@"com.facebook.sdk:TokenInformationLoginTypeLoginKey"] = @0;

    return [FBAccessTokenData createTokenFromDictionary: tokenInformationDictionary];
}

然后使用上面的类来创建

MySessionTokenCachingStrategy* tokenCachingStrategy = 
[[MySessionTokenCachingStrategy alloc] initWithToken:token
                                      andPermissions:@[@"read_stream"]];



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

    if (session.state == FBSessionStateCreatedTokenLoaded)
    {
        // Set the active session
        [FBSession setActiveSession: session];

        // Open the session, but do not use iOS6 system acount login
        // if the caching strategy does not store info locally on the
        // device, otherwise you could use:
        // FBSessionLoginBehaviorUseSystemAccountIfPresent
        [session openWithBehavior: FBSessionLoginBehaviorWithFallbackToWebView
                completionHandler: ^(FBSession *session,
                                     FBSessionState state,
                                     NSError *error) {
                    if (!error)
                    {
                        if (session.isOpen)
                        {
                            successBlock();
                        }
                    }
                    else
                    {
                        failureBlock([error description]);
                    }
                }];
    }

【讨论】:

  • 谢谢@Mike M,你为我节省了很多时间!
  • 我建议在将每个变量添加到 NSMutableDictionary 之前检查每个变量的 nil,我已经看到将 nil 字符串添加到 TokenInformationTokenKey 字段导致崩溃。我信任 ACAccountStore 会给我一个带有非零 oAuth 令牌的帐户,但这并不总是正确的
  • 我建议在实际创建令牌策略之前完成此操作,因为如果其中一个变量不存在或不正确,它将静默失败。这将比在实际调用代码之前进行分支更难调试。
  • 我对您提供的答案有点迷茫。您应该创建一个新类,将其子类化为 FBSessionTokenCachingStrategy,并且在实现中只添加您列出的一个方法,然后当您想要打开 FBSession 时,使用第二个代码块?这些属性是从哪里来的?你能提供更多细节吗?
  • FBSession 对象是用一个 FBSessionTokenCachingStrategy 实例构造的。这些是 FB 框架提供的类。有一个默认实例,我建议通过继承它来创建自己的实例。该类有一个名为“fetchFBAccessTokenData”的getter,您想要覆盖它,如上所示。然后实例化你的子类并将实例传递给 FBSession 构造函数。
【解决方案2】:

这不是因为你首先需要一些读取权限,然后才能请求其他的吗?

【讨论】:

    【解决方案3】:

    您正在执行[[FBSession alloc] initWithPermissions:@[@"publish_actions"]],这意味着您的会话只会询问并“拥有”publish_actions 的权限,但请查看错误中的令牌:

    com.facebook.sdk:ErrorSessionKey=<FBSession: 0xa2b62a0, state: FBSessionStateOpen, loginHandler: 0xa29e9b0, appID: 131721883664256, urlSchemeSuffix: , tokenCachingStrategy:<FBSessionTokenCachingStrategy: 0xa273f60>, expirationDate: 4001-01-01 00:00:00 +0000, refreshDate: 2013-07-26 16:21:10 +0000, attemptedRefreshDate: 0001-12-30 00:00:00 +0000, permissions:(
       email,
       "publish_actions"
    )
    

    您的令牌也已经拥有email 权限。您认为这可能是问题所在吗?

    尝试使用[[FBSession alloc] initWithPermissions:@[@"publish_actions", @"email"]] 进行实例化并检查是否仍有问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-25
      • 2020-01-09
      • 1970-01-01
      • 2012-11-27
      相关资源
      最近更新 更多