Finish updating all sample apps to handle rerequest of permissions properly.

This commit is contained in:
Blake Bender 2015-08-06 15:25:17 -07:00
Родитель 33b069ef95
Коммит 74e65c4616
24 изменённых файлов: 861 добавлений и 583 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -1,4 +1,5 @@
.nuget
*.csproj.user
*.opensdf
*.sdf
*.suo

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

@ -318,6 +318,7 @@ popd
<ClInclude Include="..\..\FBWinSDK\FBWinSDK.Shared\FacebookMediaObject.h" />
<ClInclude Include="..\..\FBWinSDK\FBWinSDK.Shared\FacebookMediaStream.h" />
<ClInclude Include="..\..\FBWinSDK\FBWinSDK.Shared\FacebookPaginatedArray.h" />
<ClInclude Include="..\..\FBWinSDK\FBWinSDK.Shared\FacebookPermissions.h" />
<ClInclude Include="..\..\FBWinSDK\FBWinSDK.Shared\FacebookProfilePicture.h" />
<ClInclude Include="..\..\FBWinSDK\FBWinSDK.Shared\FacebookProfilePictureControl.xaml.h">
<DependentUpon>..\..\FBWinSDK\FBWinSDK.Shared\FacebookProfilePictureControl.xaml</DependentUpon>
@ -353,6 +354,7 @@ popd
<ClCompile Include="..\..\FBWinSDK\FBWinSDK.Shared\FacebookMediaObject.cpp" />
<ClCompile Include="..\..\FBWinSDK\FBWinSDK.Shared\FacebookMediaStream.cpp" />
<ClCompile Include="..\..\FBWinSDK\FBWinSDK.Shared\FacebookPaginatedArray.cpp" />
<ClCompile Include="..\..\FBWinSDK\FBWinSDK.Shared\FacebookPermissions.cpp" />
<ClCompile Include="..\..\FBWinSDK\FBWinSDK.Shared\FacebookProfilePicture.cpp" />
<ClCompile Include="..\..\FBWinSDK\FBWinSDK.Shared\FacebookProfilePictureControl.xaml.cpp">
<DependentUpon>..\..\FBWinSDK\FBWinSDK.Shared\FacebookProfilePictureControl.xaml</DependentUpon>

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

@ -120,6 +120,9 @@
<ClCompile Include="..\..\FBWinSDK\FBWinSDK.Shared\ScaleConverter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\FBWinSDK\FBWinSDK.Shared\FacebookPermissions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\FBWinSDK\FBWinSDK.Shared\FacebookAccessTokenData.h">
@ -205,6 +208,9 @@
<ClInclude Include="..\..\FBWinSDK\FBWinSDK.Shared\ScaleConverter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\FBWinSDK\FBWinSDK.Shared\FacebookPermissions.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Page Include="..\..\FBWinSDK\FBWinSDK.Shared\FacebookProfilePictureControl.xaml" />

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

@ -27,6 +27,7 @@
<ClInclude Include="$(MSBuildThisFileDirectory)FacebookMediaObject.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)FacebookMediaStream.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)FacebookPaginatedArray.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)FacebookPermissions.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)FacebookProfilePicture.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)FacebookProfilePictureControl.xaml.h">
<DependentUpon>$(MSBuildThisFileDirectory)FacebookProfilePictureControl.xaml</DependentUpon>
@ -61,6 +62,7 @@
<ClCompile Include="$(MSBuildThisFileDirectory)FacebookMediaObject.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)FacebookMediaStream.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)FacebookPaginatedArray.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)FacebookPermissions.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)Generated\FBCursors.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)Generated\FBGroup.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)Generated\FBPage.cpp" />

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

@ -81,6 +81,9 @@
<ClInclude Include="$(MSBuildThisFileDirectory)HlsColor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)FacebookPermissions.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(MSBuildThisFileDirectory)pch.cpp">
@ -154,6 +157,9 @@
<ClCompile Include="$(MSBuildThisFileDirectory)HlsColor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)FacebookPermissions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="Header Files">

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

@ -31,6 +31,7 @@ namespace Facebook
*/
public enum class ErrorSubcode : int
{
ErrorSubcodeAppNotAuthorized = 458,
ErrorSubcodeSessionInvalidated = 466
};

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

@ -17,6 +17,7 @@
#include "pch.h"
#include "FacebookLoginButton.h"
#include "FacebookSession.h"
#include "FacebookPermissions.h"
using namespace Concurrency;
using namespace Facebook;
@ -32,7 +33,6 @@ FBLoginButton::FBLoginButton() :
{
String^ styleKey = FBLoginButton::typeid->FullName;
this->DefaultStyleKey = styleKey;
m_permissions = ref new Vector<String^>();
}
void FBLoginButton::OnApplyTemplate(
@ -58,61 +58,21 @@ void FBLoginButton::OnApplyTemplate(
//}
//
IVector<String^>^ FBLoginButton::Permissions::get()
FBPermissions^ FBLoginButton::Permissions::get()
{
return m_permissions;
}
void FBLoginButton::Permissions::set(IVector<String^>^ Values)
void FBLoginButton::Permissions::set(FBPermissions^ Permissions)
{
m_permissions->Clear();
IIterator<String^>^ it = nullptr;
for (it = Values->First(); it->HasCurrent; it->MoveNext())
{
String^ value = it->Current;
m_permissions->Append(value);
}
m_permissions = Permissions;
}
void FBLoginButton::InitWithPermissions(
IVector<String^>^ permissions
FBPermissions^ Permissions
)
{
if (!m_permissions)
{
m_permissions = ref new Vector<String^>(0);
}
m_permissions->Clear();
for (IIterator<String^>^ iter = permissions->First();
iter->HasCurrent;
iter->MoveNext())
{
m_permissions->Append(iter->Current);
}
}
String^ FBLoginButton::GetPermissions(
)
{
String^ permissions = nullptr;
if (m_permissions)
{
permissions = ref new String();
for (unsigned int i = 0; i < m_permissions->Size; i++)
{
if (i)
{
permissions += ",";
}
permissions += m_permissions->GetAt(i);
}
}
return permissions;
m_permissions = Permissions;
}
void FBLoginButton::OnClick(
@ -128,14 +88,7 @@ void FBLoginButton::OnClick(
}
else
{
String^ permissions = GetPermissions();
PropertySet^ parameters = ref new PropertySet();
if (permissions != nullptr)
{
parameters->Insert(L"scope", permissions);
}
create_task(s->LoginAsync(parameters))
create_task(s->LoginAsync(m_permissions))
.then([=](FBResult^ result)
{
if (result->Succeeded)

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

@ -17,6 +17,7 @@
#pragma once
#include "FacebookSession.h"
#include "FacebookPermissions.h"
namespace Facebook
{
@ -58,16 +59,16 @@ namespace Facebook
//}
//! Publish permissions for user
property Windows::Foundation::Collections::IVector<Platform::String^>^
property Facebook::FBPermissions^
Permissions
{
Windows::Foundation::Collections::IVector<Platform::String^>^ get();
void set(Windows::Foundation::Collections::IVector<Platform::String^>^);
Facebook::FBPermissions^ get();
void set(Facebook::FBPermissions^);
}
//! Ask for read permissions at login
void InitWithPermissions(
Windows::Foundation::Collections::IVector<Platform::String^>^ permissions
Facebook::FBPermissions^ permissions
);
event FBLoginErrorHandler^ FBLoginError;
@ -85,6 +86,6 @@ namespace Facebook
);
// SessionLoginBehavior m_loginBehavior;
Platform::Collections::Vector<Platform::String^>^ m_permissions;
Facebook::FBPermissions^ m_permissions;
};
}

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

@ -0,0 +1,44 @@
#include <ppltasks.h>
#include "pch.h"
#include "FacebookPermissions.h"
using namespace Facebook;
using namespace Platform;
using namespace Windows::Foundation::Collections;
IVectorView<String^>^ FBPermissions::Values::get()
{
return _values;
};
void FBPermissions::Values::set(
IVectorView<String^>^ value
)
{
_values = value;
}
Platform::String^ FBPermissions::ToString(
)
{
String^ permissions = nullptr;
if (_values)
{
permissions = ref new String();
for (unsigned int i = 0; i < _values->Size; i++)
{
if (i)
{
permissions += ",";
}
permissions += _values->GetAt(i);
}
}
return permissions;
}

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

@ -0,0 +1,22 @@
#pragma once
namespace Facebook
{
public ref class FBPermissions sealed
{
public:
property Windows::Foundation::Collections::IVectorView<Platform::String^>^ Values
{
Windows::Foundation::Collections::IVectorView<Platform::String^>^ get();
void set(Windows::Foundation::Collections::IVectorView<Platform::String^>^ value);
};
virtual Platform::String^ ToString(
) override;
private:
Windows::Foundation::Collections::IVectorView<Platform::String^>^ _values;
};
}

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

@ -501,7 +501,7 @@ Windows::Foundation::IAsyncOperation<FBResult^>^ FBSession::ShowRequestsDialog(
// the concurrency event object was deprecated in the Win10 SDK tools.
// Switched to plane old Windows event, but that didn't work at all,
// so polling for now.
while (m_showingDialog && !dialogResponse);
while (m_showingDialog && !dialogResponse)
{
dialogResponse = m_dialog->GetDialogResponse();
Sleep(0);
@ -674,9 +674,6 @@ String^ FBSession::GetRedirectUriString(
)
{
Uri^ endURI = WebAuthenticationBroker::GetCurrentApplicationCallbackUri();
String^ blerg = endURI->DisplayUri;
OutputDebugString(blerg->Data());
OutputDebugString(L"\n");
return endURI->DisplayUri;
}
@ -856,22 +853,33 @@ task<FBResult^> FBSession::RunWebViewLoginOnUIThread(
}
IAsyncOperation<FBResult^>^ FBSession::LoginAsync(
PropertySet^ Parameters
FBPermissions^ Permissions
)
{
m_dialog = ref new FacebookDialog();
return create_async([=]()
{
PropertySet^ parameters = ref new PropertySet();
if (Permissions)
{
parameters->Insert(L"scope", Permissions->ToString());
}
if (LoggedIn)
{
parameters->Insert(L"auth_type", L"rerequest");
}
return create_task([=]() -> FBResult^
{
FBResult^ result = nullptr;
task<FBResult^> authTask = TryLoginViaWebView(Parameters);
task<FBResult^> authTask = TryLoginViaWebView(parameters);
result = authTask.get();
if (!result)
{
authTask = TryLoginViaWebAuthBroker(Parameters);
authTask = TryLoginViaWebAuthBroker(parameters);
result = authTask.get();
}

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

@ -20,6 +20,7 @@
#include "FacebookResult.h"
#include "FBUser.h"
#include "FacebookDialog.xaml.h"
#include "FacebookPermissions.h"
namespace Facebook
{
@ -125,7 +126,7 @@ namespace Facebook
);
Windows::Foundation::IAsyncOperation<FBResult^>^ LoginAsync(
Windows::Foundation::Collections::PropertySet^ Parameters
Facebook::FBPermissions^ Permissions
);
private:

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

@ -223,19 +223,5 @@
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<<<<<<< HEAD
<ImportGroup Label="ExtensionTargets">
<Import Project="..\packages\FBWinSDK.0.9.0\build\native\FBWinSDK.targets" Condition="Exists('..\packages\FBWinSDK.0.9.0\build\native\FBWinSDK.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\FBWinSDK.0.9.0\build\native\FBWinSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\FBWinSDK.0.9.0\build\native\FBWinSDK.props'))" />
<Error Condition="!Exists('..\packages\FBWinSDK.0.9.0\build\native\FBWinSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\FBWinSDK.0.9.0\build\native\FBWinSDK.targets'))" />
<Error Condition="!Exists('..\packages\FBWinSDK-debug.0.9.0\build\FBWinSDK-debug.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\FBWinSDK-debug.0.9.0\build\FBWinSDK-debug.props'))" />
</Target>
=======
<ImportGroup Label="ExtensionTargets" />
>>>>>>> 26_change_sample_sdk_references
</Project>

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

@ -21,13 +21,13 @@
#include "pch.h"
#include "MainPage.xaml.h"
#include "UserInfo.xaml.h"
#include "OptionsPage.xaml.h"
using namespace concurrency;
using namespace Facebook;
using namespace LoginCpp;
using namespace Platform;
using namespace Platform::Collections;
using namespace Windows::ApplicationModel;
using namespace Windows::ApplicationModel::Activation;
using namespace Windows::ApplicationModel::Core;
@ -85,21 +85,19 @@ void MainPage::SetSessionAppIds()
s->WinAppId = winAppId;
}
String^ MainPage::BuildPermissionsString(
FBPermissions^ MainPage::BuildPermissions(
)
{
String^ result = ref new String();
FBPermissions^ result = ref new FBPermissions();
Vector<String^>^ v = ref new Vector<String^>();
for (unsigned int i = 0; i < ARRAYSIZE(requested_permissions); i++)
{
if (i)
{
result += L",";
}
result += ref new String(requested_permissions[i]);
v->Append(ref new String(requested_permissions[i]));
}
result->Values = v->GetView();
return result;
}
@ -134,46 +132,95 @@ BOOL MainPage::DidGetAllRequestedPermissions(
return success;
}
BOOL MainPage::WasAppPermissionRemovedByUser(
FBResult^ result
)
{
return (result &&
(!result->Succeeded) &&
(result->ErrorInfo->Code == (int)Facebook::ErrorCode::ErrorCodeOauthException));
}
BOOL MainPage::ShouldRerequest(
FBResult^ result
)
{
return (result &&
result->Succeeded &&
!DidGetAllRequestedPermissions());
}
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)
CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
Windows::UI::Core::CoreDispatcherPriority::Normal,
ref new Windows::UI::Core::DispatchedHandler([this]()
{
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);
}));
}
}
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
)
void MainPage::TryRerequest(
BOOL retry
)
{
Parameters->Insert(L"auth_type", L"rerequest");
return create_task(FBSession::ActiveSession->Logout())
.then([=]()
{
SetSessionAppIds();
// If we're logged out, the session has cleared the FB and Windows app IDs,
// so they need to be set again. We load these IDs via the ResourceLoader
// class, which must be accessed on the UI thread, which is why this call
// is outside the task context.
SetSessionAppIds();
return FBSession::ActiveSession->LoginAsync(Parameters);
});
create_task(FBSession::ActiveSession->LoginAsync(BuildPermissions()))
.then([=](FBResult^ result)
{
if (result->Succeeded)
{
if (retry && (!DidGetAllRequestedPermissions()))
{
// Login call has to happen on UI thread, so circle back around to it
CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
Windows::UI::Core::CoreDispatcherPriority::Normal,
ref new Windows::UI::Core::DispatchedHandler([=]()
{
TryRerequest(false);
}));
}
else
{
NavigateToOptionsPage();
}
}
});
}
void MainPage::login_OnClicked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
void MainPage::LogoutAndRetry(
)
{
// It's necessary to logout prior to reattempting login, because it could
// be that the session has cached an access token that is no longer valid,
// e.g. if the user revoked the app in Settings. FBSession::Logout clears
// the session's cached access token, among other things.
create_task(FBSession::ActiveSession->Logout())
.then([=]()
{
// Login call has to happen on UI thread, so circle back around to it
CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
Windows::UI::Core::CoreDispatcherPriority::Normal,
ref new Windows::UI::Core::DispatchedHandler([=]()
{
TryRerequest(TRUE);
}));
});
}
void MainPage::login_OnClicked(
Object^ sender,
RoutedEventArgs^ e
)
{
FBSession^ sess = FBSession::ActiveSession;
@ -187,48 +234,32 @@ void MainPage::login_OnClicked(Platform::Object^ sender, Windows::UI::Xaml::Rout
}
else
{
PropertySet^ parameters = ref new PropertySet();
parameters->Insert(L"scope", BuildPermissionsString());
create_task(sess->LoginAsync(parameters)).then([=](FBResult^ result)
create_task(sess->LoginAsync(BuildPermissions())).then([=](FBResult^ result)
{
task<FBResult^> nextResult = create_task([=]()
// There may be other cases where an a failed login request should
// prompt the app to retry login, but this one is common enough that
// it's helpful to demonstrate handling it here. If the predicate
// returns TRUE, the user has gone to facebook.com in the browser,
// and removed our app from their list off allowed apps in Settings.
if (WasAppPermissionRemovedByUser(result))
{
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)
LogoutAndRetry();
}
else if (ShouldRerequest(result))
{
// Login call has to happen on UI thread, so circle back around to it
CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
Windows::UI::Core::CoreDispatcherPriority::Normal,
ref new Windows::UI::Core::DispatchedHandler([=]()
{
TryRerequest(FALSE);
}));
}
else if (result->Succeeded)
{
// Got a token and all our permissions.
NavigateToOptionsPage();
}
});
});
}
}

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

@ -37,18 +37,29 @@ namespace LoginCpp
void MainPage::SetSessionAppIds(
);
Platform::String^ BuildPermissionsString(
Facebook::FBPermissions^ BuildPermissions(
);
BOOL DidGetAllRequestedPermissions(
);
BOOL MainPage::WasAppPermissionRemovedByUser(
Facebook::FBResult^ result
);
BOOL ShouldRerequest(
Facebook::FBResult^ result
);
void NavigateToOptionsPage(
);
concurrency::task<Facebook::FBResult^> MainPage::LoginViaRerequest(
Windows::Foundation::Collections::PropertySet^ Parameters
);
void MainPage::TryRerequest(
BOOL retry
);
void MainPage::LogoutAndRetry(
);
void login_OnClicked(
Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e

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

@ -23,148 +23,198 @@
#include "MainPage.xaml.h"
#include "OptionsPage.xaml.h"
using namespace LoginCpp;
using namespace concurrency;
using namespace Facebook;
using namespace LoginCpp;
using namespace Platform;
using namespace Platform::Collections;
using namespace Windows::ApplicationModel;
using namespace Windows::ApplicationModel::Activation;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::ApplicationModel::Resources;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI::Xaml;
using namespace Windows::Security::Authentication::Web;
using namespace Windows::UI::Core;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation;
using namespace Facebook;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
#define FBAppIDName L"FBApplicationId"
#define FBStoreAppIDName L"FBWindowsAppId"
#define PermissionGranted L"granted"
const wchar_t* requested_permissions[] =
const wchar_t* requested_permissions[] =
{
L"public_profile",
L"user_friends",
L"user_likes",
L"user_groups",
L"user_location"
L"public_profile",
L"user_friends",
L"user_likes",
L"user_groups",
L"user_location"
};
MainPage::MainPage()
{
InitializeComponent();
SetSessionAppIds();
String^ whatever = WebAuthenticationBroker::GetCurrentApplicationCallbackUri()->DisplayUri + L"\n";
OutputDebugString(whatever->Data());
SetSessionAppIds();
}
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();
// 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(
)
FBPermissions^ MainPage::BuildPermissions(
)
{
String^ result = ref new String();
FBPermissions^ result = ref new FBPermissions();
Vector<String^>^ v = ref new Vector<String^>();
for (unsigned int i = 0; i < ARRAYSIZE(requested_permissions); i++)
{
if (i)
{
result += L",";
}
for (unsigned int i = 0; i < ARRAYSIZE(requested_permissions); i++)
{
v->Append(ref new String(requested_permissions[i]));
}
result += ref new String(requested_permissions[i]);
}
result->Values = v->GetView();
return result;
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;
}
BOOL MainPage::WasAppPermissionRemovedByUser(
FBResult^ result
)
{
BOOL success = FALSE;
FBAccessTokenData^ data = FBSession::ActiveSession->AccessTokenData;
unsigned int grantedCount = 0;
return (result &&
(!result->Succeeded) &&
((result->ErrorInfo->Code == (int)Facebook::ErrorCode::ErrorCodeOauthException) &&
(result->ErrorInfo->Subcode == (int)Facebook::ErrorSubcode::ErrorSubcodeSessionInvalidated)));
}
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;
BOOL MainPage::ShouldRerequest(
FBResult^ result
)
{
return (result &&
result->Succeeded &&
!DidGetAllRequestedPermissions());
}
void MainPage::NavigateToOptionsPage()
{
LoginButton->Content = L"Logout";
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);
}));
}
}
CoreApplication::MainView->CoreWindow->Dispatcher->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
void MainPage::TryRerequest(
BOOL retry
)
{
Parameters->Insert(L"auth_type", L"rerequest");
return create_task(FBSession::ActiveSession->Logout())
// If we're logged out, the session has cleared the FB and Windows app IDs,
// so they need to be set again. We load these IDs via the ResourceLoader
// class, which must be accessed on the UI thread, which is why this call
// is outside the task context.
SetSessionAppIds();
create_task(FBSession::ActiveSession->LoginAsync(BuildPermissions()))
.then([=](FBResult^ result)
{
if (result->Succeeded)
{
if (retry && (!DidGetAllRequestedPermissions()))
{
// Login call has to happen on UI thread, so circle back around to it
CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
Windows::UI::Core::CoreDispatcherPriority::Normal,
ref new Windows::UI::Core::DispatchedHandler([=]()
{
TryRerequest(false);
}));
}
else
{
NavigateToOptionsPage();
}
}
});
}
void MainPage::LogoutAndRetry(
)
{
// It's necessary to logout prior to reattempting login, because it could
// be that the session has cached an access token that is no longer valid,
// e.g. if the user revoked the app in Settings. FBSession::Logout clears
// the session's cached access token, among other things.
create_task(FBSession::ActiveSession->Logout())
.then([=]()
{
SetSessionAppIds();
return FBSession::ActiveSession->LoginAsync(Parameters);
// Login call has to happen on UI thread, so circle back around to it
CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
Windows::UI::Core::CoreDispatcherPriority::Normal,
ref new Windows::UI::Core::DispatchedHandler([=]()
{
TryRerequest(TRUE);
}));
});
}
@ -182,49 +232,32 @@ void MainPage::login_OnClicked(Platform::Object^ sender, Windows::UI::Xaml::Rout
}
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);
create_task(sess->LoginAsync(BuildPermissions())).then([=](FBResult^ result)
{
// There may be other cases where an a failed login request should
// prompt the app to retry login, but this one is common enough that
// it's helpful to demonstrate handling it here. If the predicate
// returns TRUE, the user has gone to facebook.com in the browser,
// and removed our app from their list off allowed apps in Settings.
if (WasAppPermissionRemovedByUser(result))
{
LogoutAndRetry();
}
return nextResult;
})
.then([=](FBResult^ loginResult)
{
task<FBResult^> finalResult = create_task([=]()
else if (ShouldRerequest(result))
{
return loginResult;
});
if (loginResult->Succeeded)
{
if (!DidGetAllRequestedPermissions())
// Login call has to happen on UI thread, so circle back around to it
CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
Windows::UI::Core::CoreDispatcherPriority::Normal,
ref new Windows::UI::Core::DispatchedHandler([=]()
{
finalResult = LoginViaRerequest(parameters);
}
}
return finalResult;
})
.then([=](FBResult^ finalResult)
{
if (finalResult->Succeeded)
{
NavigateToOptionsPage();
TryRerequest(FALSE);
}));
}
else if (result && result->Succeeded)
{
// Got a token, and all the permissions we wanted - go ahead to the options page
NavigateToOptionsPage();
}
});
}
}

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

@ -33,23 +33,36 @@ namespace LoginCpp
public:
MainPage();
private:
void MainPage::SetSessionAppIds(
private:
void MainPage::SetSessionAppIds(
);
Facebook::FBPermissions^ BuildPermissions(
);
BOOL DidGetAllRequestedPermissions(
);
BOOL MainPage::WasAppPermissionRemovedByUser(
Facebook::FBResult^ result
);
Platform::String^ BuildPermissionsString(
BOOL ShouldRerequest(
Facebook::FBResult^ result
);
BOOL DidGetAllRequestedPermissions(
void NavigateToOptionsPage(
);
void MainPage::TryRerequest(
BOOL retry
);
void NavigateToOptionsPage(
void MainPage::LogoutAndRetry(
);
concurrency::task<Facebook::FBResult^> MainPage::LoginViaRerequest(
Windows::Foundation::Collections::PropertySet^ Parameters
);
void login_OnClicked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
void login_OnClicked(
Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e
);
};
}

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

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<DebuggerFlavor>WindowsPhoneEmulatorDebugger</DebuggerFlavor>
<WindowsPhoneEmulatorID>8BDF218D-FDBB-4A97-90F9-3AA33B559A92;Mobile Emulator 10.0.10240.0 WVGA 4 inch 512MB</WindowsPhoneEmulatorID>
</PropertyGroup>
</Project>

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

@ -9,7 +9,7 @@
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Button x:Name ="LoginButton" Content="Login" HorizontalAlignment="Left" Margin="39,48,0,0" VerticalAlignment="Top" Click="LoginButton_Click" Width="315"/>
<Button x:Name ="LoginButton" Content="Login" HorizontalAlignment="Left" Margin="39,48,0,0" VerticalAlignment="Top" Click="login_OnClicked" Width="315"/>
<TextBlock FontSize="14" HorizontalAlignment="Left" Margin="39,302,0,0" TextWrapping="Wrap" Text="Access Token:" VerticalAlignment="Top" Width="261" Height="18"/>
<TextBlock x:Name="ResponseText" FontSize="14" HorizontalAlignment="Left" Margin="39,325,0,0" Text="TextBox" TextWrapping="Wrap" VerticalAlignment="Top" Height="94" Width="261"/>
<TextBlock FontSize="14" HorizontalAlignment="Left" Margin="39,445,0,0" TextWrapping="Wrap" Text="Expires" VerticalAlignment="Top" Height="24" Width="261"/>

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

@ -23,13 +23,18 @@
#include "MainPage.xaml.h"
#include "OptionsPage.xaml.h"
using namespace LoginCpp;
using namespace concurrency;
using namespace Facebook;
using namespace LoginCpp;
using namespace Platform;
using namespace Platform::Collections;
using namespace Windows::ApplicationModel;
using namespace Windows::ApplicationModel::Activation;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::ApplicationModel::Resources;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::Security::Authentication::Web;
using namespace Windows::UI::Core;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
@ -38,225 +43,221 @@ using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation;
using namespace Windows::ApplicationModel::Resources;
using namespace Windows::Globalization;
using namespace Facebook;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
#define FBAppIDName L"FBApplicationId"
#define FBPhoneAppIDName L"FBWinPhoneAppId"
#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"
L"public_profile",
L"user_friends",
L"user_likes",
L"user_groups",
L"user_location"
};
MainPage::MainPage()
{
InitializeComponent();
SetSessionAppIds();
}
InitializeComponent();
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached. The Parameter
/// property is typically used to configure the page.</param>
void MainPage::OnNavigatedTo(NavigationEventArgs^ e)
{
(void)e; // Unused parameter
String^ whatever = WebAuthenticationBroker::GetCurrentApplicationCallbackUri()->DisplayUri + L"\n";
OutputDebugString(whatever->Data());
// TODO: Prepare page for display here.
// TODO: If your application contains multiple pages, ensure that you are
// handling the hardware Back button by registering for the
// Windows::Phone::UI::Input::HardwareButtons.BackPressed event.
// If you are using the NavigationHelper provided by some templates,
// this event is handled for you.
FBSession^ sess = FBSession::ActiveSession;
if (sess->LoggedIn)
{
LoginButton->Content = L"Logout";
Calendar^ cal = ref new Calendar();
cal->SetDateTime(sess->AccessTokenData->ExpirationDate);
ResponseText->Text = sess->AccessTokenData->AccessToken;
ExpirationDate->Text = cal->DayOfWeekAsString() + "," + cal->YearAsString() + "/" +
cal->MonthAsNumericString() + "/" + cal->DayAsString() + ", " +
cal->HourAsPaddedString(2) + ":" + cal->MinuteAsPaddedString(2) + ":" +
cal->SecondAsPaddedString(2);
}
SetSessionAppIds();
}
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();
// 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(FBPhoneAppIDName);
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(
)
FBPermissions^ MainPage::BuildPermissions(
)
{
String^ result = ref new String();
FBPermissions^ result = ref new FBPermissions();
Vector<String^>^ v = ref new Vector<String^>();
for (unsigned int i = 0; i < ARRAYSIZE(requested_permissions); i++)
{
if (i)
{
result += L",";
}
for (unsigned int i = 0; i < ARRAYSIZE(requested_permissions); i++)
{
v->Append(ref new String(requested_permissions[i]));
}
result += ref new String(requested_permissions[i]);
}
result->Values = v->GetView();
return result;
return result;
}
BOOL MainPage::DidGetAllRequestedPermissions(
)
)
{
BOOL success = FALSE;
FBAccessTokenData^ data = FBSession::ActiveSession->AccessTokenData;
unsigned int grantedCount = 0;
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 (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;
}
}
if (grantedCount == ARRAYSIZE(requested_permissions))
{
success = TRUE;
}
}
return success;
return success;
}
BOOL MainPage::WasAppPermissionRemovedByUser(
FBResult^ result
)
{
return (result &&
(!result->Succeeded) &&
((result->ErrorInfo->Code == (int)Facebook::ErrorCode::ErrorCodeOauthException) &&
(result->ErrorInfo->Subcode == (int)Facebook::ErrorSubcode::ErrorSubcodeSessionInvalidated)));
}
BOOL MainPage::ShouldRerequest(
FBResult^ result
)
{
return (result &&
result->Succeeded &&
!DidGetAllRequestedPermissions());
}
void MainPage::NavigateToOptionsPage()
{
LoginButton->Content = L"Logout";
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);
}));
}
}
CoreApplication::MainView->CoreWindow->Dispatcher->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
)
void MainPage::TryRerequest(
BOOL retry
)
{
Parameters->Insert(L"auth_type", L"rerequest");
return create_task(FBSession::ActiveSession->Logout())
.then([=]()
{
SetSessionAppIds();
// If we're logged out, the session has cleared the FB and Windows app IDs,
// so they need to be set again. We load these IDs via the ResourceLoader
// class, which must be accessed on the UI thread, which is why this call
// is outside the task context.
SetSessionAppIds();
return FBSession::ActiveSession->LoginAsync(Parameters);
});
create_task(FBSession::ActiveSession->LoginAsync(BuildPermissions()))
.then([=](FBResult^ result)
{
if (result->Succeeded)
{
if (retry && (!DidGetAllRequestedPermissions()))
{
// Login call has to happen on UI thread, so circle back around to it
CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
Windows::UI::Core::CoreDispatcherPriority::Normal,
ref new Windows::UI::Core::DispatchedHandler([=]()
{
TryRerequest(false);
}));
}
else
{
NavigateToOptionsPage();
}
}
});
}
void MainPage::LoginButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
void MainPage::LogoutAndRetry(
)
{
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();
}
});
}
// It's necessary to logout prior to reattempting login, because it could
// be that the session has cached an access token that is no longer valid,
// e.g. if the user revoked the app in Settings. FBSession::Logout clears
// the session's cached access token, among other things.
create_task(FBSession::ActiveSession->Logout())
.then([=]()
{
// Login call has to happen on UI thread, so circle back around to it
CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
Windows::UI::Core::CoreDispatcherPriority::Normal,
ref new Windows::UI::Core::DispatchedHandler([=]()
{
TryRerequest(TRUE);
}));
});
}
void MainPage::login_OnClicked(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
{
create_task(sess->LoginAsync(BuildPermissions())).then([=](FBResult^ result)
{
// There may be other cases where an a failed login request should
// prompt the app to retry login, but this one is common enough that
// it's helpful to demonstrate handling it here. If the predicate
// returns TRUE, the user has gone to facebook.com in the browser,
// and removed our app from their list off allowed apps in Settings.
if (WasAppPermissionRemovedByUser(result))
{
LogoutAndRetry();
}
else if (ShouldRerequest(result))
{
// Login call has to happen on UI thread, so circle back around to it
CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
Windows::UI::Core::CoreDispatcherPriority::Normal,
ref new Windows::UI::Core::DispatchedHandler([=]()
{
TryRerequest(FALSE);
}));
}
else if (result && result->Succeeded)
{
// Got a token, and all the permissions we wanted - go ahead to the options page
NavigateToOptionsPage();
}
});
}
}

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

@ -25,45 +25,45 @@
namespace LoginCpp
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public ref class MainPage sealed
{
public:
MainPage();
protected:
virtual void OnNavigatedTo(
Windows::UI::Xaml::Navigation::NavigationEventArgs^ e
) override;
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public ref class MainPage sealed
{
public:
MainPage();
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,
Windows::UI::Xaml::RoutedEventArgs^ e
void MainPage::SetSessionAppIds(
);
Windows::Foundation::EventRegistrationToken m_cookie;
Facebook::FBPermissions^ BuildPermissions(
);
BOOL DidGetAllRequestedPermissions(
);
BOOL MainPage::WasAppPermissionRemovedByUser(
Facebook::FBResult^ result
);
BOOL ShouldRerequest(
Facebook::FBResult^ result
);
void NavigateToOptionsPage(
);
void MainPage::TryRerequest(
BOOL retry
);
void MainPage::LogoutAndRetry(
);
void login_OnClicked(
Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e
);
void LoginButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
};
}

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

@ -1,10 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<<<<<<< HEAD
<Import Project="..\..\packages\FBWinSDK-debug.0.9.0\build\FBWinSDK-debug.props" Condition="Exists('..\..\packages\FBWinSDK-debug.0.9.0\build\FBWinSDK-debug.props')" />
<Import Project="..\..\packages\FBWinSDK.0.9.0\build\win\FBWinSDK.props" Condition="Exists('..\..\packages\FBWinSDK.0.9.0\build\win\FBWinSDK.props')" />
=======
>>>>>>> 26_change_sample_sdk_references
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

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

@ -32,6 +32,8 @@ using Windows.UI.Xaml.Navigation;
using Facebook;
using Windows.Globalization;
using Windows.ApplicationModel.Resources;
using System.Threading.Tasks;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
@ -45,11 +47,14 @@ namespace LoginCs
public MainPage()
{
this.InitializeComponent();
SetSessionAppIds();
}
private const string _granted = "granted";
private const string FBAppIDName = "FBApplicationId";
private const string FBPhoneAppIDName = "FBWinPhoneAppId";
private const string PermissionGranted = "granted";
private string[] requested_permissions =
private readonly string[] requested_permissions =
{
"public_profile",
"email",
@ -57,39 +62,55 @@ namespace LoginCs
"publish_actions"
};
private string BuildPermissionsString()
void SetSessionAppIds(
)
{
string permissions = "";
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(FBPhoneAppIDName);
// IDs are both sent to FB app, so it can validate us.
s.FBAppId = appId;
s.WinAppId = winAppId;
}
FBPermissions BuildPermissions(
)
{
FBPermissions result = new FBPermissions();
List<string> perms = new List<string>();
for (uint i = 0; i < requested_permissions.Length; i++)
{
if (i > 0)
{
permissions += ",";
}
permissions += requested_permissions[i];
perms.Add(requested_permissions[i]);
}
return permissions;
result.Values = perms;
return result;
}
private bool DidGetRequestedPermissions(
bool DidGetAllRequestedPermissions(
)
{
bool gotPermissions = false;
bool success = false;
FBAccessTokenData data = FBSession.ActiveSession.AccessTokenData;
uint grantedCount = 0;
if (FBSession.ActiveSession.AccessTokenData != null)
if (data != null)
{
IReadOnlyDictionary<string, string> Permissions =
FBSession.ActiveSession.AccessTokenData.Permissions;
for (uint i = 0; i < requested_permissions.Length; i++)
{
if (Permissions.ContainsKey(requested_permissions[i]))
string perm = requested_permissions[i];
if ((data.Permissions != null) && (data.Permissions.ContainsKey(perm)))
{
if (String.CompareOrdinal(Permissions[requested_permissions[i]], _granted) == 0)
string Value = data.Permissions[perm];
if (string.CompareOrdinal(Value, PermissionGranted) == 0)
{
grantedCount++;
}
@ -98,49 +119,53 @@ namespace LoginCs
if (grantedCount == requested_permissions.Length)
{
gotPermissions = true;
success = true;
}
}
return gotPermissions;
return success;
}
private async void LoginToFB()
bool WasAppPermissionRemovedByUser(
FBResult Result
)
{
Uri endURI =
WebAuthenticationBroker.GetCurrentApplicationCallbackUri();
string uriString = endURI.ToString();
PropertySet parameters = new PropertySet();
return ((Result != null) &&
(!Result.Succeeded) &&
(Result.ErrorInfo.Code == (int)Facebook.ErrorCode.ErrorCodeOauthException));
}
parameters.Add(new KeyValuePair<String, Object>("scope",
BuildPermissionsString()));
bool ShouldRerequest(
FBResult Result
)
{
return ((Result != null) &&
Result.Succeeded &&
!DidGetAllRequestedPermissions());
}
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);
}
async Task TryRerequest(
bool Retry
)
{
// If we're logged out, the session has cleared the FB and Windows app IDs,
// so they need to be set again. We load these IDs via the ResourceLoader
// class, which must be accessed on the UI thread, which is why this call
// is outside the task context.
SetSessionAppIds();
FBResult result = await FBSession.ActiveSession.LoginAsync(BuildPermissions());
if (result.Succeeded)
{
if (DidGetRequestedPermissions())
if (Retry && (!DidGetAllRequestedPermissions()))
{
Frame.Navigate(typeof(UserInfo));
await TryRerequest(false);
}
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));
}
//Navigate back to same page, to clear out logged in info.
App.RootFrame.Navigate(typeof(UserInfo));
}
}
}
@ -194,7 +219,27 @@ namespace LoginCs
else
{
LoginButton.Content = "Logout";
LoginToFB();
FBResult result = await sess.LoginAsync(BuildPermissions());
// There may be other cases where an a failed login request should
// prompt the app to retry login, but this one is common enough that
// it's helpful to demonstrate handling it here. If the predicate
// returns TRUE, the user has gone to facebook.com in the browser,
// and removed our app from their list off allowed apps in Settings.
if (WasAppPermissionRemovedByUser(result))
{
await sess.Logout();
await TryRerequest(true);
}
else if (ShouldRerequest(result))
{
await TryRerequest(false);
}
else if (result.Succeeded)
{
//Navigate back to same page, to clear out logged in info.
App.RootFrame.Navigate(typeof(UserInfo));
}
}
}
}

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

@ -20,6 +20,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.ApplicationModel.Resources;
using Windows.Foundation;
using Windows.Foundation.Collections;
@ -41,45 +42,133 @@ namespace LoginCs
/// </summary>
public sealed partial class MainPage : Page
{
const string FBAppIDName = "FBApplicationId";
const string FBPhoneAppIDName = "FBWinPhoneAppId";
const string FBAppIDName = "FBApplicationId";
const string FBPhoneAppIDName = "FBWinPhoneAppId";
const string PermissionGranted = "granted";
readonly string[] requested_permissions =
{
"public_profile",
"user_friends",
"user_likes",
"user_groups",
"user_location"
};
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
SetSessionAppIds();
}
public async void StartLogin(
void SetSessionAppIds(
)
{
FBSession s = FBSession.ActiveSession;
// Assumes the Facebook App ID and Windows Phone Store ID have been
// saved in the default resource file.
// 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(FBPhoneAppIDName);
// IDs are both sent to FB app, so it can validate us.
s.FBAppId = appId;
s.WinAppId = winAppId;
}
// These are the default permissions, needed to retrieve user info.
//s.AddPermission("public_profile");
//s.AddPermission("user_friends");
//s.AddPermission("user_likes");
FBPermissions BuildPermissions(
)
{
FBPermissions result = new FBPermissions();
List<string> perms = new List<string>();
PropertySet parameters = new PropertySet();
parameters.Add(
new KeyValuePair<string, object>("scope",
"public_profile,user_friends,user_likes"));
// Launches a URI to redirect to the FB app, which will log us in
// and return the result via our registered protocol.
FBResult result = await s.LoginAsync();
for (uint i = 0; i < requested_permissions.Length; i++)
{
perms.Add(requested_permissions[i]);
}
result.Values = perms;
return result;
}
bool DidGetAllRequestedPermissions(
)
{
bool success = false;
FBAccessTokenData data = FBSession.ActiveSession.AccessTokenData;
uint grantedCount = 0;
if (data != null)
{
for (uint i = 0; i < requested_permissions.Length; i++)
{
string perm = requested_permissions[i];
if ((data.Permissions != null) && (data.Permissions.ContainsKey(perm)))
{
string Value = data.Permissions[perm];
if (string.CompareOrdinal(Value, PermissionGranted) == 0)
{
grantedCount++;
}
}
}
if (grantedCount == requested_permissions.Length)
{
success = true;
}
}
return success;
}
bool WasAppPermissionRemovedByUser(
FBResult Result
)
{
return ((Result != null) &&
(!Result.Succeeded) &&
(Result.ErrorInfo.Code == (int)Facebook.ErrorCode.ErrorCodeOauthException));
}
bool ShouldRerequest(
FBResult Result
)
{
return ((Result != null) &&
Result.Succeeded &&
!DidGetAllRequestedPermissions());
}
async Task TryRerequest(
bool Retry
)
{
// If we're logged out, the session has cleared the FB and Windows app IDs,
// so they need to be set again. We load these IDs via the ResourceLoader
// class, which must be accessed on the UI thread, which is why this call
// is outside the task context.
SetSessionAppIds();
FBResult result = await FBSession.ActiveSession.LoginAsync(BuildPermissions());
if (result.Succeeded)
{
if (Retry && (!DidGetAllRequestedPermissions()))
{
await TryRerequest(false);
}
else
{
//Navigate back to same page, to clear out logged in info.
App.RootFrame.Navigate(typeof(UserInfo));
}
}
}
/// <summary>
@ -127,7 +216,27 @@ namespace LoginCs
else
{
LoginButton.Content = "Logout";
StartLogin();
FBResult result = await sess.LoginAsync(BuildPermissions());
// There may be other cases where an a failed login request should
// prompt the app to retry login, but this one is common enough that
// it's helpful to demonstrate handling it here. If the predicate
// returns TRUE, the user has gone to facebook.com in the browser,
// and removed our app from their list off allowed apps in Settings.
if (WasAppPermissionRemovedByUser(result))
{
await sess.Logout();
}
else if (ShouldRerequest(result))
{
await TryRerequest(false);
}
else if (result.Succeeded)
{
//Navigate back to same page, to clear out logged in info.
App.RootFrame.Navigate(typeof(UserInfo));
}
}
}
}