问题
I have a token but keep getting this error: "An active access token must be used to query information about the current user." Any help is appreciated :)
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];
LOG:
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
回答1:
Ok, what worked for me was using a solution from the friendpicker sample app.
Need to check if the session is opened and open it if it isn't.
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
}
}];
回答2:
I'm not certain that this is causing your problem, but I've had issues in the past with the Facebook SDK's aggressive caching. Because the Facebook SDK looks to multiple places for a valid logged in Facebook user, it short-circuits this search on subsequent calls by caching the current logged in user. If at any point one of the possible logged in Facebook user changes, or auth for that user changes, then things can go a bit crazy.
To give you an idea, the Facebook SDK tries the iOS 5+ system facebook account, inter-app calls to facebook's own native app, the browser cookie for the web view instance running in your app, or bounce you out to safari and use the browser cookie in safari... so if any one of those different logged in accounts changed, or one of those accounts revoted permissions or changed its password (for example), things can go haywire if the SDK cached too aggressively. In order to get around this, I always checked the access token against the graph api after I open a Facebook SDK session. If it passes the simple "me" test, then I'll accept this access token as valid and proceed. However, if it fails, then I flush the cached values in the SDK and force the Facebook SDK to re-open a brand new session, which would go back through all of the possible logged in Facebook accounts to find an active session. This may or may not result in a new application authentication prompt... however it should result in a working access token for you app.
Some sample code
To help you understand what I'm doing, here's some semi-pseudo code. (Unfortunately, I've abstracted away too many things to be able to easily copy-paste a working set of code here, so you'll have to fill in the blanks in a few places :P)
Main run loop
The entry point to my Facebook code starts with this if statement that looks at the current state of the Facebook SDK activeSession and either reprompts or verifies access:
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];
}
Most of the functions that are called should be pretty straight forward. For instance, runIfFullAuth
just calls whatever you want after the user has been fully authed and you have a verified access token. checkAgainstGraphAPIOnVerified:onInvalidated:onAppRemoved:
is my own function that does a simple call out to graph.facebook.com/me?fields=permissions
with the access token FBSession.activeSession.accessTokenData.accessToken
. If I get an id back in the json returned, then I have a verified access token. If I'm missing any required permissions in the json returned, then I have an invalidated access token. If I get nothing back from the graph api, then I consider that as the app being removed.
openSessionHandler
openSessionHandler
is responsible for understanding what the Facebook SDK is returning to us after we request for an open session. Here's roughly what it's doing:
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
And lastly, here's how you clear the Facebook SDK of its cached session information:
[FBSession.activeSession closeAndClearTokenInformation];
[FBSession.activeSession close];
[FBSession setActiveSession:nil];
To be honest, I don't know if that second call to close
is redundant... but this is how I've always done it.... hahaha
Oh, and at the top of my function openNewFBSession
, which I call whenever I need to force the Facebook SDK to start over and search for a new Facebook session, I call my clearCachedFBInfo
function. That guarantees I have no cached Facebook information in the SDK, and then I go and open a new session.
In the end, I still don't know if this is causing the problem that you're seeing, but I've definitely experienced very nasty issues with seemingly valid access tokens that are not valid in the past, and this is how I fixed my problems. Good luck! And I'm happy to answer any questions that you may have!
来源:https://stackoverflow.com/questions/16594947/ios-facebook-sdk-an-active-access-token-must-be-used-to-query-information-about