Fix up other sample apps to handle app deauthorized and individual permissions revoked by re-requesting.

This commit is contained in:
Blake Bender 2015-07-24 14:36:45 -07:00
Родитель 5400c4d092
Коммит aa5cd013a5
10 изменённых файлов: 556 добавлений и 166 удалений

Просмотреть файл

@ -86,7 +86,14 @@ DateTime FBAccessTokenData::ExpirationDate::get()
IMapView<String^, String^>^ FBAccessTokenData::Permissions::get()
{
return m_permissions->GetView();
IMapView<String^, String^>^ result = nullptr;
if (m_permissions)
{
result = m_permissions->GetView();
}
return result;
}
String^ FBAccessTokenData::UserID::get()

Просмотреть файл

@ -19,19 +19,19 @@
namespace Facebook
{
/*!
* \brief error categories.
* \brief error codes.
*/
public enum class ErrorCategory
public enum class ErrorCode : int
{
ErrorCategoryInvalid = 0,
ErrorCategoryRetry = 1,
ErrorCategoryAuthenticateReopenSession = 2,
ErrorCategoryPermissions = 3,
ErrorCategoryServer = 4,
ErrorCategoryThrottling = 5,
ErrorCategoryUserCancelled = 6,
ErrorCategoryFacebookOther = -1,
ErrorCategoryBadRequest = -2
ErrorCodeOauthException = 190
};
/*!
* \brief error subcodes.
*/
public enum class ErrorSubcode : int
{
ErrorSubcodeSessionInvalidated = 466
};
/*!

Просмотреть файл

@ -854,10 +854,9 @@ IAsyncOperation<FBResult^>^ FBSession::LoginAsync(
return create_task([=]() -> FBResult^
{
FBResult^ result = nullptr;
task<FBResult^> authTask;
//task<FBResult^> authTask = TryLoginViaWebView(Parameters);
//result = authTask.get();
task<FBResult^> authTask = TryLoginViaWebView(Parameters);
result = authTask.get();
if (!result)
{
authTask = TryLoginViaWebAuthBroker(Parameters);
@ -873,6 +872,16 @@ IAsyncOperation<FBResult^>^ FBSession::LoginAsync(
.then([this](FBResult^ userInfoResult) -> task<FBResult^>
{
return TryGetAppPermissionsAfterLogin(userInfoResult);
})
.then([=](FBResult^ finalResult)
{
if (!finalResult->Succeeded)
{
m_loggedIn = false;
AccessTokenData = nullptr;
}
return finalResult;
});
});
}

Просмотреть файл

@ -63,22 +63,26 @@ MainPage::MainPage()
{
InitializeComponent();
FBSession^ s = FBSession::ActiveSession;
String^ whatever = WebAuthenticationBroker::GetCurrentApplicationCallbackUri()->DisplayUri + L"\n";
OutputDebugString(whatever->Data());
// Assumes the Facebook App ID and Windows Phone Store ID have been saved
// in the default resource file.
// TODO: Commenting this out for now - resource loader isn't working for me in UWP app.
ResourceLoader^ rl = ResourceLoader::GetForCurrentView();
SetSessionAppIds();
}
String^ appId = rl->GetString(FBAppIDName);
String^ winAppId = rl->GetString(FBStoreAppIDName);
void MainPage::SetSessionAppIds()
{
FBSession^ s = FBSession::ActiveSession;
// IDs are both sent to FB app, so it can validate us.
s->FBAppId = appId;
s->WinAppId = winAppId;
// Assumes the Facebook App ID and Windows Phone Store ID have been saved
// in the default resource file.
ResourceLoader^ rl = ResourceLoader::GetForCurrentView();
String^ appId = rl->GetString(FBAppIDName);
String^ winAppId = rl->GetString(FBStoreAppIDName);
// IDs are both sent to FB app, so it can validate us.
s->FBAppId = appId;
s->WinAppId = winAppId;
}
String^ MainPage::BuildPermissionsString(
@ -98,6 +102,7 @@ String^ MainPage::BuildPermissionsString(
return result;
}
BOOL MainPage::DidGetAllRequestedPermissions(
)
{
@ -110,7 +115,7 @@ BOOL MainPage::DidGetAllRequestedPermissions(
for (unsigned int i = 0; i < ARRAYSIZE(requested_permissions); i++)
{
String^ perm = ref new String(requested_permissions[i]);
if (data->Permissions->HasKey(perm))
if (data->Permissions && (data->Permissions->HasKey(perm)))
{
String^ Value = data->Permissions->Lookup(perm);
if (!String::CompareOrdinal(Value, PermissionGranted))
@ -154,6 +159,20 @@ void MainPage::NavigateToOptionsPage()
}
}
task<FBResult^> MainPage::LoginViaRerequest(
PropertySet^ Parameters
)
{
Parameters->Insert(L"auth_type", L"rerequest");
return create_task(FBSession::ActiveSession->Logout())
.then([=]()
{
SetSessionAppIds();
return FBSession::ActiveSession->LoginAsync(Parameters);
});
}
void MainPage::login_OnClicked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
FBSession^ sess = FBSession::ActiveSession;
@ -172,28 +191,44 @@ void MainPage::login_OnClicked(Platform::Object^ sender, Windows::UI::Xaml::Rout
parameters->Insert(L"scope", BuildPermissionsString());
create_task(sess->LoginAsync(parameters)).then([=](FBResult^ result)
{
if (result->Succeeded)
{
if (DidGetAllRequestedPermissions())
create_task(sess->LoginAsync(parameters)).then([=](FBResult^ result)
{
task<FBResult^> nextResult = create_task([=]()
{
return result;
});
if ((!result->Succeeded) &&
((result->ErrorInfo->Code == 190) && (result->ErrorInfo->Subcode == 466)))
{
nextResult = LoginViaRerequest(parameters);
}
return nextResult;
})
.then([=](FBResult^ loginResult)
{
task<FBResult^> finalResult = create_task([=]()
{
return loginResult;
});
if (loginResult->Succeeded)
{
if (!DidGetAllRequestedPermissions())
{
NavigateToOptionsPage();
finalResult = LoginViaRerequest(parameters);
}
else
{
parameters->Insert(L"scope", BuildPermissionsString());
parameters->Insert(L"auth_type", L"rerequest");
create_task(sess->LoginAsync(parameters))
.then([=](FBResult^ result)
{
if (result->Succeeded)
{
NavigateToOptionsPage();
}
});
}
}
});
}
return finalResult;
})
.then([=](FBResult^ finalResult)
{
if (finalResult->Succeeded)
{
NavigateToOptionsPage();
}
});
}
}

Просмотреть файл

@ -34,6 +34,9 @@ namespace LoginCpp
MainPage();
private:
void MainPage::SetSessionAppIds(
);
Platform::String^ BuildPermissionsString(
);
@ -43,6 +46,10 @@ namespace LoginCpp
void NavigateToOptionsPage(
);
concurrency::task<Facebook::FBResult^> MainPage::LoginViaRerequest(
Windows::Foundation::Collections::PropertySet^ Parameters
);
void login_OnClicked(
Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e
);

Просмотреть файл

@ -47,72 +47,184 @@ using namespace Facebook;
#define FBAppIDName L"FBApplicationId"
#define FBStoreAppIDName L"FBWindowsAppId"
#define PermissionGranted L"granted"
const wchar_t* requested_permissions[] =
{
L"public_profile",
L"user_friends",
L"user_likes",
L"user_groups",
L"user_location"
};
MainPage::MainPage()
{
InitializeComponent();
SetSessionAppIds();
}
// Assumes the Facebook App ID and Windows Phone Store ID have been saved
// in the default resource file.
ResourceLoader^ rl = ResourceLoader::GetForCurrentView();
void MainPage::SetSessionAppIds()
{
FBSession^ s = FBSession::ActiveSession;
FBSession^ s = FBSession::ActiveSession;
// Assumes the Facebook App ID and Windows Phone Store ID have been saved
// in the default resource file.
ResourceLoader^ rl = ResourceLoader::GetForCurrentView();
String^ appId = rl->GetString(FBAppIDName);
String^ winAppId = rl->GetString(FBStoreAppIDName);
String^ appId = rl->GetString(FBAppIDName);
String^ winAppId = rl->GetString(FBStoreAppIDName);
// IDs are both sent to FB app, so it can validate us.
s->FBAppId = appId;
s->WinAppId = winAppId;
}
// IDs are both sent to FB app, so it can validate us.
s->FBAppId = appId;
s->WinAppId = winAppId;
String^ MainPage::BuildPermissionsString(
)
{
String^ result = ref new String();
for (unsigned int i = 0; i < ARRAYSIZE(requested_permissions); i++)
{
if (i)
{
result += L",";
}
result += ref new String(requested_permissions[i]);
}
return result;
}
BOOL MainPage::DidGetAllRequestedPermissions(
)
{
BOOL success = FALSE;
FBAccessTokenData^ data = FBSession::ActiveSession->AccessTokenData;
unsigned int grantedCount = 0;
if (data)
{
for (unsigned int i = 0; i < ARRAYSIZE(requested_permissions); i++)
{
String^ perm = ref new String(requested_permissions[i]);
if (data->Permissions && (data->Permissions->HasKey(perm)))
{
String^ Value = data->Permissions->Lookup(perm);
if (!String::CompareOrdinal(Value, PermissionGranted))
{
grantedCount++;
}
}
}
if (grantedCount == ARRAYSIZE(requested_permissions))
{
success = TRUE;
}
}
return success;
}
void MainPage::NavigateToOptionsPage()
{
LoginButton->Content = L"Logout";
// We're redirecting to a page that shows simple user info, so
// have to dispatch back to the UI thread.
CoreWindow^ wind = CoreApplication::MainView->CoreWindow;
if (wind)
{
CoreDispatcher^ disp = wind->Dispatcher;
if (disp)
{
disp->RunAsync(
Windows::UI::Core::CoreDispatcherPriority::Normal,
ref new Windows::UI::Core::DispatchedHandler([this]()
{
LoginCpp::App^ a = dynamic_cast<LoginCpp::App^>(Application::Current);
Windows::UI::Xaml::Controls::Frame^ f = a->CreateRootFrame();
f->Navigate(OptionsPage::typeid);
}));
}
}
}
task<FBResult^> MainPage::LoginViaRerequest(
PropertySet^ Parameters
)
{
Parameters->Insert(L"auth_type", L"rerequest");
return create_task(FBSession::ActiveSession->Logout())
.then([=]()
{
SetSessionAppIds();
return FBSession::ActiveSession->LoginAsync(Parameters);
});
}
void MainPage::login_OnClicked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
FBSession^ sess = FBSession::ActiveSession;
FBSession^ sess = FBSession::ActiveSession;
if (sess->LoggedIn)
{
sess->Logout();
LoginButton->Content = L"Logout";
LoginCpp::App^ a = dynamic_cast<LoginCpp::App^>(Application::Current);
Windows::UI::Xaml::Controls::Frame^ f = a->CreateRootFrame();
f->Navigate(MainPage::typeid);
}
else
{
sess->AddPermission("public_profile");
sess->AddPermission("user_friends");
sess->AddPermission("user_likes");
sess->AddPermission("user_groups");
sess->AddPermission("user_location");
if (sess->LoggedIn)
{
sess->Logout();
LoginButton->Content = L"Logout";
LoginCpp::App^ a = dynamic_cast<LoginCpp::App^>(Application::Current);
Windows::UI::Xaml::Controls::Frame^ f = a->CreateRootFrame();
f->Navigate(MainPage::typeid);
}
else
{
PropertySet^ parameters = ref new PropertySet();
create_task(sess->LoginAsync()).then([=](FBResult^ result)
{
if (result->Succeeded)
{
LoginButton->Content = L"Logout";
parameters->Insert(L"scope", BuildPermissionsString());
// We're redirecting to a page that shows simple user info, so
// have to dispatch back to the UI thread.
CoreWindow^ wind = CoreApplication::MainView->CoreWindow;
create_task(sess->LoginAsync(parameters)).then([=](FBResult^ result)
{
task<FBResult^> nextResult = create_task([=]()
{
return result;
});
if (wind)
{
CoreDispatcher^ disp = wind->Dispatcher;
if (disp)
{
disp->RunAsync(
Windows::UI::Core::CoreDispatcherPriority::Normal,
ref new Windows::UI::Core::DispatchedHandler([this]()
{
LoginCpp::App^ a = dynamic_cast<LoginCpp::App^>(Application::Current);
Windows::UI::Xaml::Controls::Frame^ f = a->CreateRootFrame();
f->Navigate(OptionsPage::typeid);
}));
}
}
}
});
}
if ((!result->Succeeded) &&
((result->ErrorInfo->Code == 190) && (result->ErrorInfo->Subcode == 466)))
{
nextResult = LoginViaRerequest(parameters);
}
return nextResult;
})
.then([=](FBResult^ loginResult)
{
task<FBResult^> finalResult = create_task([=]()
{
return loginResult;
});
if (loginResult->Succeeded)
{
if (!DidGetAllRequestedPermissions())
{
finalResult = LoginViaRerequest(parameters);
}
}
return finalResult;
})
.then([=](FBResult^ finalResult)
{
if (finalResult->Succeeded)
{
NavigateToOptionsPage();
}
});
}
}

Просмотреть файл

@ -34,6 +34,22 @@ namespace LoginCpp
MainPage();
private:
void login_OnClicked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
void MainPage::SetSessionAppIds(
);
Platform::String^ BuildPermissionsString(
);
BOOL DidGetAllRequestedPermissions(
);
void NavigateToOptionsPage(
);
concurrency::task<Facebook::FBResult^> MainPage::LoginViaRerequest(
Windows::Foundation::Collections::PropertySet^ Parameters
);
void login_OnClicked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
};
}

Просмотреть файл

@ -46,25 +46,22 @@ using namespace Facebook;
#define FBAppIDName L"FBApplicationId"
#define FBPhoneAppIDName L"FBWinPhoneAppId"
#define PermissionGranted L"granted"
const wchar_t* requested_permissions[] =
{
L"public_profile",
L"user_friends",
L"user_likes",
L"user_groups",
L"user_location"
};
MainPage::MainPage()
{
InitializeComponent();
// Assumes the Facebook App ID and Windows Phone Store ID have been saved
// in the default resource file.
ResourceLoader^ rl = ResourceLoader::GetForCurrentView();
FBSession^ s = FBSession::ActiveSession;
String^ appId = rl->GetString(FBAppIDName);
String^ winAppId = rl->GetString(FBPhoneAppIDName);
// IDs are both sent to FB app, so it can validate us.
s->FBAppId = appId;
s->WinAppId = winAppId;
SetSessionAppIds();
}
/// <summary>
@ -100,57 +97,166 @@ void MainPage::OnNavigatedTo(NavigationEventArgs^ e)
}
}
void LoginCpp::MainPage::LoginButton_Click(
Platform::Object^ sender,
Windows::UI::Xaml::RoutedEventArgs^ e
)
void MainPage::SetSessionAppIds()
{
// Get the active session, set it up with the parameters it needs, and
// start Login process.
FBSession^ sess = FBSession::ActiveSession;
FBSession^ s = FBSession::ActiveSession;
if (sess->LoggedIn)
{
sess->Logout();
LoginButton->Content = L"Login";
LoginCpp::App^ a = dynamic_cast<LoginCpp::App^>(Application::Current);
Windows::UI::Xaml::Controls::Frame^ f = a->CreateRootFrame();
f->Navigate(MainPage::typeid);
}
else
{
sess->AddPermission("public_profile");
sess->AddPermission("user_friends");
sess->AddPermission("user_likes");
sess->AddPermission("user_groups");
sess->AddPermission("user_location");
// Assumes the Facebook App ID and Windows Phone Store ID have been saved
// in the default resource file.
ResourceLoader^ rl = ResourceLoader::GetForCurrentView();
create_task(sess->LoginAsync()).then([=](FBResult^ result)
{
if (result->Succeeded)
{
LoginButton->Content = L"Logout";
String^ appId = rl->GetString(FBAppIDName);
String^ winAppId = rl->GetString(FBPhoneAppIDName);
// We're redirecting to a page that shows simple user info, so
// have to dispatch back to the UI thread.
CoreWindow^ wind = CoreApplication::MainView->CoreWindow;
if (wind)
{
CoreDispatcher^ disp = wind->Dispatcher;
if (disp)
{
disp->RunAsync(
Windows::UI::Core::CoreDispatcherPriority::Normal,
ref new Windows::UI::Core::DispatchedHandler([this]()
{
LoginCpp::App^ a = dynamic_cast<LoginCpp::App^>(Application::Current);
Windows::UI::Xaml::Controls::Frame^ f = a->CreateRootFrame();
f->Navigate(OptionsPage::typeid);
}));
}
}
}
});
}
// IDs are both sent to FB app, so it can validate us.
s->FBAppId = appId;
s->WinAppId = winAppId;
}
String^ MainPage::BuildPermissionsString(
)
{
String^ result = ref new String();
for (unsigned int i = 0; i < ARRAYSIZE(requested_permissions); i++)
{
if (i)
{
result += L",";
}
result += ref new String(requested_permissions[i]);
}
return result;
}
BOOL MainPage::DidGetAllRequestedPermissions(
)
{
BOOL success = FALSE;
FBAccessTokenData^ data = FBSession::ActiveSession->AccessTokenData;
unsigned int grantedCount = 0;
if (data)
{
for (unsigned int i = 0; i < ARRAYSIZE(requested_permissions); i++)
{
String^ perm = ref new String(requested_permissions[i]);
if (data->Permissions && (data->Permissions->HasKey(perm)))
{
String^ Value = data->Permissions->Lookup(perm);
if (!String::CompareOrdinal(Value, PermissionGranted))
{
grantedCount++;
}
}
}
if (grantedCount == ARRAYSIZE(requested_permissions))
{
success = TRUE;
}
}
return success;
}
void MainPage::NavigateToOptionsPage()
{
LoginButton->Content = L"Logout";
// We're redirecting to a page that shows simple user info, so
// have to dispatch back to the UI thread.
CoreWindow^ wind = CoreApplication::MainView->CoreWindow;
if (wind)
{
CoreDispatcher^ disp = wind->Dispatcher;
if (disp)
{
disp->RunAsync(
Windows::UI::Core::CoreDispatcherPriority::Normal,
ref new Windows::UI::Core::DispatchedHandler([this]()
{
LoginCpp::App^ a = dynamic_cast<LoginCpp::App^>(Application::Current);
Windows::UI::Xaml::Controls::Frame^ f = a->CreateRootFrame();
f->Navigate(OptionsPage::typeid);
}));
}
}
}
task<FBResult^> MainPage::LoginViaRerequest(
PropertySet^ Parameters
)
{
Parameters->Insert(L"auth_type", L"rerequest");
return create_task(FBSession::ActiveSession->Logout())
.then([=]()
{
SetSessionAppIds();
return FBSession::ActiveSession->LoginAsync(Parameters);
});
}
void MainPage::LoginButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
FBSession^ sess = FBSession::ActiveSession;
if (sess->LoggedIn)
{
sess->Logout();
LoginButton->Content = L"Logout";
LoginCpp::App^ a = dynamic_cast<LoginCpp::App^>(Application::Current);
Windows::UI::Xaml::Controls::Frame^ f = a->CreateRootFrame();
f->Navigate(MainPage::typeid);
}
else
{
PropertySet^ parameters = ref new PropertySet();
parameters->Insert(L"scope", BuildPermissionsString());
create_task(sess->LoginAsync(parameters)).then([=](FBResult^ result)
{
task<FBResult^> nextResult = create_task([=]()
{
return result;
});
if ((!result->Succeeded) &&
((result->ErrorInfo->Code == 190) && (result->ErrorInfo->Subcode == 466)))
{
nextResult = LoginViaRerequest(parameters);
}
return nextResult;
})
.then([=](FBResult^ loginResult)
{
task<FBResult^> finalResult = create_task([=]()
{
return loginResult;
});
if (loginResult->Succeeded)
{
if (!DidGetAllRequestedPermissions())
{
finalResult = LoginViaRerequest(parameters);
}
}
return finalResult;
})
.then([=](FBResult^ finalResult)
{
if (finalResult->Succeeded)
{
NavigateToOptionsPage();
}
});
}
}

Просмотреть файл

@ -41,7 +41,23 @@ namespace LoginCpp
private:
void StartLogin(
Facebook::FBSession^ Session
);
);
void MainPage::SetSessionAppIds(
);
Platform::String^ BuildPermissionsString(
);
BOOL DidGetAllRequestedPermissions(
);
void NavigateToOptionsPage(
);
concurrency::task<Facebook::FBResult^> MainPage::LoginViaRerequest(
Windows::Foundation::Collections::PropertySet^ Parameters
);
void LoginButton_Click(
Platform::Object^ sender,

Просмотреть файл

@ -47,6 +47,64 @@ namespace LoginCs
this.InitializeComponent();
}
private const string _granted = "granted";
private string[] requested_permissions =
{
"public_profile",
"email",
"user_friends",
"publish_actions"
};
private string BuildPermissionsString()
{
string permissions = "";
for (uint i = 0; i < requested_permissions.Length; i++)
{
if (i > 0)
{
permissions += ",";
}
permissions += requested_permissions[i];
}
return permissions;
}
private bool DidGetRequestedPermissions(
)
{
bool gotPermissions = false;
uint grantedCount = 0;
if (FBSession.ActiveSession.AccessTokenData != null)
{
IReadOnlyDictionary<string, string> Permissions =
FBSession.ActiveSession.AccessTokenData.Permissions;
for (uint i = 0; i < requested_permissions.Length; i++)
{
if (Permissions.ContainsKey(requested_permissions[i]))
{
if (String.CompareOrdinal(Permissions[requested_permissions[i]], _granted) == 0)
{
grantedCount++;
}
}
}
if (grantedCount == requested_permissions.Length)
{
gotPermissions = true;
}
}
return gotPermissions;
}
private async void LoginToFB()
{
Uri endURI =
@ -55,11 +113,35 @@ namespace LoginCs
PropertySet parameters = new PropertySet();
parameters.Add(new KeyValuePair<String, Object>("scope",
"public_profile,email,user_friends,publish_actions"));
BuildPermissionsString()));
FBResult result = await FBSession.ActiveSession.LoginAsync(parameters);
if ((!result.Succeeded) &&
(((ErrorCode)result.ErrorInfo.Code == ErrorCode.ErrorCodeOauthException) &&
((ErrorSubcode)result.ErrorInfo.Subcode == ErrorSubcode.ErrorSubcodeSessionInvalidated)))
{
parameters.Add(new KeyValuePair<String, Object>("auth_type", "rerequest"));
result = await FBSession.ActiveSession.LoginAsync(parameters);
}
if (result.Succeeded)
{
Frame.Navigate(typeof(UserInfo));
if (DidGetRequestedPermissions())
{
Frame.Navigate(typeof(UserInfo));
}
else
{
if (!parameters.ContainsKey("auth_type"))
{
parameters.Add(new KeyValuePair<String, Object>("auth_type", "rerequest"));
}
result = await FBSession.ActiveSession.LoginAsync(parameters);
if (result.Succeeded)
{
Frame.Navigate(typeof(UserInfo));
}
}
}
}