4

我有一个令牌,但不断收到此错误:“必须使用活动访问令牌来查询有关当前用户的信息。” 任何帮助表示赞赏:)

    NSLog(@"TOKEN : %@",[[FBSession activeSession] accessToken]);

    NSString *picture = [NSString stringWithFormat:@"http://www.prowebdev.org/WooF/API/OpenGraph.php"];
    NSString *image = [NSString stringWithFormat:@"http://www.prowebdev.org/WooF/API/upload/356.jpg"];
    NSString *imageBool = [NSString stringWithFormat:@"true"];

    NSMutableDictionary *myDictionary = [NSMutableDictionary dictionaryWithObjects:[NSArray arrayWithObjects:picture,image,imageBool, nil] forKeys:[NSArray arrayWithObjects:@"picture",@"image[0][url]",@"image[1][user_generated]", nil]];

    FBRequest *request  = [FBRequest requestWithGraphPath:@"me/mydogwoofs:posted" parameters:myDictionary HTTPMethod:@"POST"];
    FBRequestConnection *connection  = [[FBRequestConnection alloc] init];
    [connection addRequest:request completionHandler:
     ^(FBRequestConnection *connection, id result, NSError *error) {
         if (!error && result) {
             NSLog(@"Posted!");
         }else{
             NSLog(@"ERROR - %@", error);
         }
     }];
    [connection start];

日志:

TOKEN : CAAD2QmzDZCHUBALgvURs9AmdO0ZCyj4Uws1pHbX9FYMbptaZAehn6318DEQPyiWpCDWs5O4DXoyAHiBajy37HAdkO648mOgpOZCxc73JhR9n0eO3KejeEkmgKTNSJti2GRmGuZCfhVm9X4cQhhk35ksfEdN8AGR7R6aP3dZBGFWQZDZD

Error: HTTP status code: 400
ERROR - Error Domain=com.facebook.sdk Code=5 "The operation couldn’t be completed. (com.facebook.sdk error 5.)" UserInfo=0x8b8abd0 {com.facebook.sdk:ParsedJSONResponseKey=<CFBasicHash 0x8b88fe0 [0x1bc3b48]>{type = mutable dict, count = 2,
entries =>
1 : <CFString 0x952a8 [0x1bc3b48]>{contents = "code"} = <CFNumber 0x8b885d0 [0x1bc3b48]>{value = +400, type = kCFNumberSInt32Type}
2 : <CFString 0x93eb8 [0x1bc3b48]>{contents = "body"} = <CFBasicHash 0x8b75ae0 [0x1bc3b48]>{type = mutable dict, count = 1,

entries =>
11 : <CFString 0x8b88f20 [0x1bc3b48]>{contents = "error"} = <CFBasicHash 0x8b888d0 [0x1bc3b48]>{type = mutable dict, count = 3,

entries =>
2 : <CFString 0x8b5f550 [0x1bc3b48]>{contents = "type"} = <CFString 0x8b88aa0 [0x1bc3b48]>{contents = "OAuthException"}
3 : <CFString 0x8b88a40 [0x1bc3b48]>{contents = "message"} = <CFString 0x8b889a0 [0x1bc3b48]>{contents = "An active access token must be used to query information about the current user."}
6 : <CFString 0x8b88e40 [0x1bc3b48]>{contents = "code"} = 2500
4

2 回答 2

8

好的,对我有用的是使用来自friendpicker示例应用程序的解决方案。

需要检查会话是否打开,如果没有打开。

if (!FBSession.activeSession.isOpen) {
    // if the session is closed, then we open it here, and establish a handler for state changes
    [FBSession openActiveSessionWithReadPermissions:nil
                                       allowLoginUI:YES
                                  completionHandler:^(FBSession *session,
                                                         FBSessionState state,
                                                         NSError *error) {
        if (error) {
            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error"
                                                                message:error.localizedDescription
                                                               delegate:nil
                                                      cancelButtonTitle:@"OK"
                                                      otherButtonTitles:nil];
            [alertView show];
        } else if (session.isOpen) {
            //run your user info request here
        }
    }];
于 2013-06-11T17:33:50.553 回答
3

我不确定这是否会导致您的问题,但我过去曾遇到过 Facebook SDK 激进缓存的问题。因为 Facebook SDK 会在多个位置查找有效的登录 Facebook 用户,所以它通过缓存当前登录用户来缩短后续调用的搜索。如果在任何时候可能登录的 Facebook 用户之一发生变化,或者该用户的身份验证发生变化,那么事情可能会变得有点疯狂。

为了给你一个想法,Facebook SDK 会尝试 iOS 5+ 系统 facebook 帐户、对 facebook 自己的原生应用程序的应用程序间调用、在你的应用程序中运行的 web 视图实例的浏览器 cookie,或者将你弹回 safari 并使用safari 中的浏览器 cookie ......因此,如果这些不同的登录帐户中的任何一个发生了更改,或者其中一个帐户撤销了权限或更改了其密码(例如),如果 SDK 缓存过于激进,事情就会变得混乱。为了解决这个问题,我总是在打开 Facebook SDK 会话后对照图形 api 检查访问令牌。如果它通过了简单的“我”测试,那么我将接受此访问令牌为有效并继续。但是,如果失败,我会刷新 SDK 中的缓存值并强制 Facebook SDK 重新打开一个全新的会话,这将返回所有可能登录的 Facebook 帐户以查找活动会话。这可能会或可能不会导致新的应用程序身份验证提示......但是它应该会为您的应用程序产生一个有效的访问令牌。

一些示例代码

为了帮助您理解我在做什么,这里有一些半伪代码。(不幸的是,我已经抽象了太多东西,无法在此处轻松复制粘贴一组工作代码,因此您必须在几个地方填写空白:P)

主运行循环

我的 Facebook 代码的入口点以这个 if 语句开头,它查看 Facebook SDK activeSession 的当前状态,并重新提示或验证访问:

if (isSet(FBSession.activeSession) &&
    (FBSession.activeSession.isOpen || FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded))
{
    // Make sure the access_token is still authed and has the correct permissions first (can't trust what's cached by fb's sdk)
    [self checkAgainstGraphAPIOnVerified:^
    {
        // From the api the access_token looks ready, make sure fb sdk session is open as well
        if (FBSession.activeSession.isOpen)
        {
            // We're authenticated and session is open, good to go
            [self runIfFullAuth];
        }
        else if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded)
        {
            // We have a cached token (permissions all look good), we need to re-open the fb sdk session
            [FBSession.activeSession openWithBehavior:FBSessionLoginBehaviorUseSystemAccountIfPresent
                                    completionHandler:openSessionHandler];
        }
    }
    onInvalidated:^
    {
        // App isn't removed, but don't have required permissions anymore...
        if (FBSession.activeSession.isOpen)
        {
            // We have an open fb session, so just reprompt for permissions
            [self repromptForPermissions];
        }
        else if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded)
        {
            // We have a cached token, we need re-open the session first before reprompting
            [FBSession.activeSession openWithBehavior:FBSessionLoginBehaviorUseSystemAccountIfPresent
                                    completionHandler:openSessionHandler];
        }
    }
    onAppRemoved:^
    {
        // App is completely removed, so prompt for permissions
        [self openNewFBSession];
    }];
}
else
{
    // No valid access_token cached, prompt for permissions
    [self openNewFBSession];
}

大多数被调用的函数应该非常简单。例如,runIfFullAuth在用户完全通过身份验证并且您拥有经过验证的访问令牌后,只需调用您想要的任何内容。 checkAgainstGraphAPIOnVerified:onInvalidated:onAppRemoved:是我自己的函数,它graph.facebook.com/me?fields=permissions使用访问令牌进行简单的调用FBSession.activeSession.accessTokenData.accessToken。如果我在返回的 json 中得到一个 id,那么我就有一个经过验证的访问令牌。如果我在返回的 json 中缺少任何必需的权限,那么我有一个无效的访问令牌。如果我从图形 api 中没有得到任何回报,那么我认为这是应用程序被删除。

openSessionHandler

openSessionHandler负责了解在我们请求开放会话后 Facebook SDK 返回给我们的内容。这大致是它在做什么:

void(^openSessionHandler)(FBSession *, FBSessionState, NSError *) = ^(FBSession *session, FBSessionState status, NSError *error) {
{
    if (error)
    {
        // Analyze the error
        if (error.fberrorShouldNotifyUser)
        {
            // Pop up alert for error
            if ([error.userInfo[FBErrorLoginFailedReason] isEqualToString:FBErrorLoginFailedReasonSystemDisallowedWithoutErrorValue])
            {
                // App disabled in facebook settings... pop up alert
            }
            else if ...
            else if ...
            else if ...
            else
            {
                // Show pop up alert with error.fberrorUserMessage
            }
            [self runIfNoAuth];
        }
        else if (error.fberrorCategory == FBErrorCategoryUserCancelled)
        {
            // User canceled
            [self runIfNoAuth];
        }
        else if (error.fberrorCategory == FBErrorCategoryAuthenticationReopenSession)
        {
            [self repromptForPermissions];
        }
        else
        {
            // Something else happened... probably network issue with Facebook servers
            [self runIfNoAuth];
        }
    }
    else
    {
        switch (status)
        {
            case FBSessionStateOpen:
            {
                [self checkAgainstGraphAPIOnVerified:^
                {
                    [self runIfFullAuth];
                }
                onInvalidated:^
                {
                    [self repromptForPermissions];
                }
                onAppRemoved:^
                {
                    // If we're here, then we're in a fucked up state.  We just prompted the user for auth, and
                    // the facebook sdk thinks we have an open session, but an api call proves that we're not actually
                    // authed.  A few possible ways to get to this point:
                    // 1) The multi-screen auth inside facebook's ios app is used (ie. not system facebook account) and
                    //      the user grants general permissions, but before granting posting permission (second page),
                    //      goes to facebook.com and removes application permissions
                    // 2) The user's facebook account password has changed, and the phone's system facebook account
                    //      hasn't been updated with the new password

                    // Pop up alert... tell user to check their Facebook settings
                    [self runIfNoAuth];
                }];
                break;
            }

            case FBSessionStateClosed:
            case FBSessionStateClosedLoginFailed:
            {
                [self clearCachedFBInfo];

                // If you want, you can choose to reprompt the user for permissions here... but it would most likely result in an endless loop where the only way out is for the user to log in :)
                [self runIfNoAuth];
                break;
            }

            default:
                break;
        }
    }
};

clearCachedFBInfo

最后,以下是清除 Facebook SDK 缓存会话信息的方法:

[FBSession.activeSession closeAndClearTokenInformation];
[FBSession.activeSession close];
[FBSession setActiveSession:nil];

老实说,我不知道第二次打电话close是不是多余的……但我一直都是这样做的……哈哈哈

哦,在我的函数顶部,openNewFBSession每当我需要强制 Facebook SDK 重新开始并搜索新的 Facebook 会话时,我都会调用它,我调用我的clearCachedFBInfo函数。这保证了我在 SDK 中没有缓存 Facebook 信息,然后我去打开一个新会话。

最后,我仍然不知道这是否会导致您所看到的问题,但我确实遇到过看似有效的访问令牌在过去无效的非常讨厌的问题,这就是我修复的方法我的问题。祝你好运!我很乐意回答您可能有的任何问题!

于 2013-06-13T08:51:39.673 回答