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 .nuget
*.csproj.user
*.opensdf *.opensdf
*.sdf *.sdf
*.suo *.suo

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -17,6 +17,7 @@
#pragma once #pragma once
#include "FacebookSession.h" #include "FacebookSession.h"
#include "FacebookPermissions.h"
namespace Facebook namespace Facebook
{ {
@ -58,16 +59,16 @@ namespace Facebook
//} //}
//! Publish permissions for user //! Publish permissions for user
property Windows::Foundation::Collections::IVector<Platform::String^>^ property Facebook::FBPermissions^
Permissions Permissions
{ {
Windows::Foundation::Collections::IVector<Platform::String^>^ get(); Facebook::FBPermissions^ get();
void set(Windows::Foundation::Collections::IVector<Platform::String^>^); void set(Facebook::FBPermissions^);
} }
//! Ask for read permissions at login //! Ask for read permissions at login
void InitWithPermissions( void InitWithPermissions(
Windows::Foundation::Collections::IVector<Platform::String^>^ permissions Facebook::FBPermissions^ permissions
); );
event FBLoginErrorHandler^ FBLoginError; event FBLoginErrorHandler^ FBLoginError;
@ -85,6 +86,6 @@ namespace Facebook
); );
// SessionLoginBehavior m_loginBehavior; // 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. // the concurrency event object was deprecated in the Win10 SDK tools.
// Switched to plane old Windows event, but that didn't work at all, // Switched to plane old Windows event, but that didn't work at all,
// so polling for now. // so polling for now.
while (m_showingDialog && !dialogResponse); while (m_showingDialog && !dialogResponse)
{ {
dialogResponse = m_dialog->GetDialogResponse(); dialogResponse = m_dialog->GetDialogResponse();
Sleep(0); Sleep(0);
@ -674,9 +674,6 @@ String^ FBSession::GetRedirectUriString(
) )
{ {
Uri^ endURI = WebAuthenticationBroker::GetCurrentApplicationCallbackUri(); Uri^ endURI = WebAuthenticationBroker::GetCurrentApplicationCallbackUri();
String^ blerg = endURI->DisplayUri;
OutputDebugString(blerg->Data());
OutputDebugString(L"\n");
return endURI->DisplayUri; return endURI->DisplayUri;
} }
@ -856,22 +853,33 @@ task<FBResult^> FBSession::RunWebViewLoginOnUIThread(
} }
IAsyncOperation<FBResult^>^ FBSession::LoginAsync( IAsyncOperation<FBResult^>^ FBSession::LoginAsync(
PropertySet^ Parameters FBPermissions^ Permissions
) )
{ {
m_dialog = ref new FacebookDialog(); m_dialog = ref new FacebookDialog();
return create_async([=]() 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^ return create_task([=]() -> FBResult^
{ {
FBResult^ result = nullptr; FBResult^ result = nullptr;
task<FBResult^> authTask = TryLoginViaWebView(Parameters); task<FBResult^> authTask = TryLoginViaWebView(parameters);
result = authTask.get(); result = authTask.get();
if (!result) if (!result)
{ {
authTask = TryLoginViaWebAuthBroker(Parameters); authTask = TryLoginViaWebAuthBroker(parameters);
result = authTask.get(); result = authTask.get();
} }

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

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

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

@ -223,19 +223,5 @@
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <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" /> <ImportGroup Label="ExtensionTargets" />
>>>>>>> 26_change_sample_sdk_references
</Project> </Project>

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

@ -21,13 +21,13 @@
#include "pch.h" #include "pch.h"
#include "MainPage.xaml.h" #include "MainPage.xaml.h"
#include "UserInfo.xaml.h"
#include "OptionsPage.xaml.h" #include "OptionsPage.xaml.h"
using namespace concurrency; using namespace concurrency;
using namespace Facebook; using namespace Facebook;
using namespace LoginCpp; using namespace LoginCpp;
using namespace Platform; using namespace Platform;
using namespace Platform::Collections;
using namespace Windows::ApplicationModel; using namespace Windows::ApplicationModel;
using namespace Windows::ApplicationModel::Activation; using namespace Windows::ApplicationModel::Activation;
using namespace Windows::ApplicationModel::Core; using namespace Windows::ApplicationModel::Core;
@ -85,21 +85,19 @@ void MainPage::SetSessionAppIds()
s->WinAppId = winAppId; 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++) for (unsigned int i = 0; i < ARRAYSIZE(requested_permissions); i++)
{ {
if (i) v->Append(ref new String(requested_permissions[i]));
{
result += L",";
}
result += ref new String(requested_permissions[i]);
} }
result->Values = v->GetView();
return result; return result;
} }
@ -134,46 +132,95 @@ BOOL MainPage::DidGetAllRequestedPermissions(
return success; 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() void MainPage::NavigateToOptionsPage()
{ {
LoginButton->Content = L"Logout"; LoginButton->Content = L"Logout";
// We're redirecting to a page that shows simple user info, so CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
// have to dispatch back to the UI thread. Windows::UI::Core::CoreDispatcherPriority::Normal,
CoreWindow^ wind = CoreApplication::MainView->CoreWindow; ref new Windows::UI::Core::DispatchedHandler([this]()
if (wind)
{ {
CoreDispatcher^ disp = wind->Dispatcher; LoginCpp::App^ a = dynamic_cast<LoginCpp::App^>(Application::Current);
if (disp) Windows::UI::Xaml::Controls::Frame^ f = a->CreateRootFrame();
{ f->Navigate(OptionsPage::typeid);
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( void MainPage::TryRerequest(
PropertySet^ Parameters BOOL retry
) )
{ {
Parameters->Insert(L"auth_type", L"rerequest"); // If we're logged out, the session has cleared the FB and Windows app IDs,
return create_task(FBSession::ActiveSession->Logout()) // so they need to be set again. We load these IDs via the ResourceLoader
.then([=]() // class, which must be accessed on the UI thread, which is why this call
{ // is outside the task context.
SetSessionAppIds(); 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; FBSession^ sess = FBSession::ActiveSession;
@ -187,48 +234,32 @@ void MainPage::login_OnClicked(Platform::Object^ sender, Windows::UI::Xaml::Rout
} }
else else
{ {
PropertySet^ parameters = ref new PropertySet(); create_task(sess->LoginAsync(BuildPermissions())).then([=](FBResult^ result)
parameters->Insert(L"scope", BuildPermissionsString());
create_task(sess->LoginAsync(parameters)).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; LogoutAndRetry();
}); }
else if (ShouldRerequest(result))
if ((!result->Succeeded) && {
((result->ErrorInfo->Code == 190) && (result->ErrorInfo->Subcode == 466))) // Login call has to happen on UI thread, so circle back around to it
{ CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
nextResult = LoginViaRerequest(parameters); Windows::UI::Core::CoreDispatcherPriority::Normal,
} ref new Windows::UI::Core::DispatchedHandler([=]()
{
return nextResult; TryRerequest(FALSE);
}) }));
.then([=](FBResult^ loginResult) }
{ else if (result->Succeeded)
task<FBResult^> finalResult = create_task([=]()
{
return loginResult;
});
if (loginResult->Succeeded)
{
if (!DidGetAllRequestedPermissions())
{
finalResult = LoginViaRerequest(parameters);
}
}
return finalResult;
})
.then([=](FBResult^ finalResult)
{
if (finalResult->Succeeded)
{ {
// Got a token and all our permissions.
NavigateToOptionsPage(); NavigateToOptionsPage();
} }
}); });
} }
} }

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

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

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

@ -23,148 +23,198 @@
#include "MainPage.xaml.h" #include "MainPage.xaml.h"
#include "OptionsPage.xaml.h" #include "OptionsPage.xaml.h"
using namespace LoginCpp;
using namespace concurrency; using namespace concurrency;
using namespace Facebook;
using namespace LoginCpp;
using namespace Platform; using namespace Platform;
using namespace Platform::Collections;
using namespace Windows::ApplicationModel; using namespace Windows::ApplicationModel;
using namespace Windows::ApplicationModel::Activation; using namespace Windows::ApplicationModel::Activation;
using namespace Windows::ApplicationModel::Core; using namespace Windows::ApplicationModel::Core;
using namespace Windows::ApplicationModel::Resources; using namespace Windows::ApplicationModel::Resources;
using namespace Windows::Foundation; using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections; 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::Core;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls; using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives; using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data; using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input; using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media; using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation; 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 FBAppIDName L"FBApplicationId"
#define FBStoreAppIDName L"FBWindowsAppId" #define FBStoreAppIDName L"FBWindowsAppId"
#define PermissionGranted L"granted" #define PermissionGranted L"granted"
const wchar_t* requested_permissions[] = const wchar_t* requested_permissions[] =
{ {
L"public_profile", L"public_profile",
L"user_friends", L"user_friends",
L"user_likes", L"user_likes",
L"user_groups", L"user_groups",
L"user_location" L"user_location"
}; };
MainPage::MainPage() MainPage::MainPage()
{ {
InitializeComponent(); InitializeComponent();
SetSessionAppIds();
String^ whatever = WebAuthenticationBroker::GetCurrentApplicationCallbackUri()->DisplayUri + L"\n";
OutputDebugString(whatever->Data());
SetSessionAppIds();
} }
void MainPage::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 // Assumes the Facebook App ID and Windows Phone Store ID have been saved
// in the default resource file. // in the default resource file.
ResourceLoader^ rl = ResourceLoader::GetForCurrentView(); ResourceLoader^ rl = ResourceLoader::GetForCurrentView();
String^ appId = rl->GetString(FBAppIDName); String^ appId = rl->GetString(FBAppIDName);
String^ winAppId = rl->GetString(FBStoreAppIDName); String^ winAppId = rl->GetString(FBStoreAppIDName);
// IDs are both sent to FB app, so it can validate us. // IDs are both sent to FB app, so it can validate us.
s->FBAppId = appId; s->FBAppId = appId;
s->WinAppId = winAppId; 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++) for (unsigned int i = 0; i < ARRAYSIZE(requested_permissions); i++)
{ {
if (i) v->Append(ref new String(requested_permissions[i]));
{ }
result += L",";
}
result += ref new String(requested_permissions[i]); result->Values = v->GetView();
}
return result; return result;
} }
BOOL MainPage::DidGetAllRequestedPermissions( 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; return (result &&
FBAccessTokenData^ data = FBSession::ActiveSession->AccessTokenData; (!result->Succeeded) &&
unsigned int grantedCount = 0; ((result->ErrorInfo->Code == (int)Facebook::ErrorCode::ErrorCodeOauthException) &&
(result->ErrorInfo->Subcode == (int)Facebook::ErrorSubcode::ErrorSubcodeSessionInvalidated)));
}
if (data) BOOL MainPage::ShouldRerequest(
{ FBResult^ result
for (unsigned int i = 0; i < ARRAYSIZE(requested_permissions); i++) )
{ {
String^ perm = ref new String(requested_permissions[i]); return (result &&
if (data->Permissions && (data->Permissions->HasKey(perm))) result->Succeeded &&
{ !DidGetAllRequestedPermissions());
String^ Value = data->Permissions->Lookup(perm);
if (!String::CompareOrdinal(Value, PermissionGranted))
{
grantedCount++;
}
}
}
if (grantedCount == ARRAYSIZE(requested_permissions))
{
success = TRUE;
}
}
return success;
} }
void MainPage::NavigateToOptionsPage() void MainPage::NavigateToOptionsPage()
{ {
LoginButton->Content = L"Logout"; LoginButton->Content = L"Logout";
// We're redirecting to a page that shows simple user info, so CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
// have to dispatch back to the UI thread. Windows::UI::Core::CoreDispatcherPriority::Normal,
CoreWindow^ wind = CoreApplication::MainView->CoreWindow; ref new Windows::UI::Core::DispatchedHandler([this]()
{
if (wind) LoginCpp::App^ a = dynamic_cast<LoginCpp::App^>(Application::Current);
{ Windows::UI::Xaml::Controls::Frame^ f = a->CreateRootFrame();
CoreDispatcher^ disp = wind->Dispatcher; f->Navigate(OptionsPage::typeid);
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( void MainPage::TryRerequest(
PropertySet^ Parameters BOOL retry
) )
{ {
Parameters->Insert(L"auth_type", L"rerequest"); // If we're logged out, the session has cleared the FB and Windows app IDs,
return create_task(FBSession::ActiveSession->Logout()) // 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([=]() .then([=]()
{ {
SetSessionAppIds(); // Login call has to happen on UI thread, so circle back around to it
CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
return FBSession::ActiveSession->LoginAsync(Parameters); 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 else
{ {
PropertySet^ parameters = ref new PropertySet(); create_task(sess->LoginAsync(BuildPermissions())).then([=](FBResult^ result)
{
parameters->Insert(L"scope", BuildPermissionsString()); // 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
create_task(sess->LoginAsync(parameters)).then([=](FBResult^ result) // it's helpful to demonstrate handling it here. If the predicate
{ // returns TRUE, the user has gone to facebook.com in the browser,
task<FBResult^> nextResult = create_task([=]() // and removed our app from their list off allowed apps in Settings.
{ if (WasAppPermissionRemovedByUser(result))
return result; {
}); LogoutAndRetry();
if ((!result->Succeeded) &&
((result->ErrorInfo->Code == 190) && (result->ErrorInfo->Subcode == 466)))
{
nextResult = LoginViaRerequest(parameters);
} }
else if (ShouldRerequest(result))
return nextResult;
})
.then([=](FBResult^ loginResult)
{
task<FBResult^> finalResult = create_task([=]()
{ {
return loginResult; // Login call has to happen on UI thread, so circle back around to it
}); CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
Windows::UI::Core::CoreDispatcherPriority::Normal,
if (loginResult->Succeeded) ref new Windows::UI::Core::DispatchedHandler([=]()
{
if (!DidGetAllRequestedPermissions())
{ {
finalResult = LoginViaRerequest(parameters); TryRerequest(FALSE);
} }));
}
return finalResult;
})
.then([=](FBResult^ finalResult)
{
if (finalResult->Succeeded)
{
NavigateToOptionsPage();
} }
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: public:
MainPage(); MainPage();
private: private:
void MainPage::SetSessionAppIds( 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( void login_OnClicked(
Windows::Foundation::Collections::PropertySet^ Parameters 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}"> Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid> <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 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 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"/> <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 "MainPage.xaml.h"
#include "OptionsPage.xaml.h" #include "OptionsPage.xaml.h"
using namespace LoginCpp;
using namespace concurrency; using namespace concurrency;
using namespace Facebook;
using namespace LoginCpp;
using namespace Platform; 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::Core;
using namespace Windows::ApplicationModel::Resources;
using namespace Windows::Foundation; using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections; using namespace Windows::Foundation::Collections;
using namespace Windows::Security::Authentication::Web;
using namespace Windows::UI::Core; using namespace Windows::UI::Core;
using namespace Windows::UI::Xaml; using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls; 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::Input;
using namespace Windows::UI::Xaml::Media; using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation; 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 FBAppIDName L"FBApplicationId"
#define FBPhoneAppIDName L"FBWinPhoneAppId" #define FBStoreAppIDName L"FBWindowsAppId"
#define PermissionGranted L"granted" #define PermissionGranted L"granted"
const wchar_t* requested_permissions[] = const wchar_t* requested_permissions[] =
{ {
L"public_profile", L"public_profile",
L"user_friends", L"user_friends",
L"user_likes", L"user_likes",
L"user_groups", L"user_groups",
L"user_location" L"user_location"
}; };
MainPage::MainPage() MainPage::MainPage()
{ {
InitializeComponent(); InitializeComponent();
SetSessionAppIds();
}
/// <summary> String^ whatever = WebAuthenticationBroker::GetCurrentApplicationCallbackUri()->DisplayUri + L"\n";
/// Invoked when this page is about to be displayed in a Frame. OutputDebugString(whatever->Data());
/// </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
// TODO: Prepare page for display here. SetSessionAppIds();
// 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);
}
} }
void MainPage::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 // Assumes the Facebook App ID and Windows Phone Store ID have been saved
// in the default resource file. // in the default resource file.
ResourceLoader^ rl = ResourceLoader::GetForCurrentView(); ResourceLoader^ rl = ResourceLoader::GetForCurrentView();
String^ appId = rl->GetString(FBAppIDName); String^ appId = rl->GetString(FBAppIDName);
String^ winAppId = rl->GetString(FBPhoneAppIDName); String^ winAppId = rl->GetString(FBStoreAppIDName);
// IDs are both sent to FB app, so it can validate us. // IDs are both sent to FB app, so it can validate us.
s->FBAppId = appId; s->FBAppId = appId;
s->WinAppId = winAppId; 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++) for (unsigned int i = 0; i < ARRAYSIZE(requested_permissions); i++)
{ {
if (i) v->Append(ref new String(requested_permissions[i]));
{ }
result += L",";
}
result += ref new String(requested_permissions[i]); result->Values = v->GetView();
}
return result; return result;
} }
BOOL MainPage::DidGetAllRequestedPermissions( BOOL MainPage::DidGetAllRequestedPermissions(
) )
{ {
BOOL success = FALSE; BOOL success = FALSE;
FBAccessTokenData^ data = FBSession::ActiveSession->AccessTokenData; FBAccessTokenData^ data = FBSession::ActiveSession->AccessTokenData;
unsigned int grantedCount = 0; unsigned int grantedCount = 0;
if (data) if (data)
{ {
for (unsigned int i = 0; i < ARRAYSIZE(requested_permissions); i++) for (unsigned int i = 0; i < ARRAYSIZE(requested_permissions); i++)
{ {
String^ perm = ref new String(requested_permissions[i]); String^ perm = ref new String(requested_permissions[i]);
if (data->Permissions && (data->Permissions->HasKey(perm))) if (data->Permissions && (data->Permissions->HasKey(perm)))
{ {
String^ Value = data->Permissions->Lookup(perm); String^ Value = data->Permissions->Lookup(perm);
if (!String::CompareOrdinal(Value, PermissionGranted)) if (!String::CompareOrdinal(Value, PermissionGranted))
{ {
grantedCount++; grantedCount++;
} }
} }
} }
if (grantedCount == ARRAYSIZE(requested_permissions)) if (grantedCount == ARRAYSIZE(requested_permissions))
{ {
success = TRUE; 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() void MainPage::NavigateToOptionsPage()
{ {
LoginButton->Content = L"Logout"; LoginButton->Content = L"Logout";
// We're redirecting to a page that shows simple user info, so CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
// have to dispatch back to the UI thread. Windows::UI::Core::CoreDispatcherPriority::Normal,
CoreWindow^ wind = CoreApplication::MainView->CoreWindow; ref new Windows::UI::Core::DispatchedHandler([this]()
{
if (wind) LoginCpp::App^ a = dynamic_cast<LoginCpp::App^>(Application::Current);
{ Windows::UI::Xaml::Controls::Frame^ f = a->CreateRootFrame();
CoreDispatcher^ disp = wind->Dispatcher; f->Navigate(OptionsPage::typeid);
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( void MainPage::TryRerequest(
PropertySet^ Parameters BOOL retry
) )
{ {
Parameters->Insert(L"auth_type", L"rerequest"); // If we're logged out, the session has cleared the FB and Windows app IDs,
return create_task(FBSession::ActiveSession->Logout()) // so they need to be set again. We load these IDs via the ResourceLoader
.then([=]() // class, which must be accessed on the UI thread, which is why this call
{ // is outside the task context.
SetSessionAppIds(); 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; // 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,
if (sess->LoggedIn) // e.g. if the user revoked the app in Settings. FBSession::Logout clears
{ // the session's cached access token, among other things.
sess->Logout(); create_task(FBSession::ActiveSession->Logout())
LoginButton->Content = L"Logout"; .then([=]()
LoginCpp::App^ a = dynamic_cast<LoginCpp::App^>(Application::Current); {
Windows::UI::Xaml::Controls::Frame^ f = a->CreateRootFrame(); // Login call has to happen on UI thread, so circle back around to it
f->Navigate(MainPage::typeid); CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
} Windows::UI::Core::CoreDispatcherPriority::Normal,
else ref new Windows::UI::Core::DispatchedHandler([=]()
{ {
PropertySet^ parameters = ref new PropertySet(); TryRerequest(TRUE);
}));
parameters->Insert(L"scope", BuildPermissionsString()); });
}
create_task(sess->LoginAsync(parameters)).then([=](FBResult^ result)
{ void MainPage::login_OnClicked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
task<FBResult^> nextResult = create_task([=]() {
{ FBSession^ sess = FBSession::ActiveSession;
return result;
}); if (sess->LoggedIn)
{
if ((!result->Succeeded) && sess->Logout();
((result->ErrorInfo->Code == 190) && (result->ErrorInfo->Subcode == 466))) LoginButton->Content = L"Logout";
{ LoginCpp::App^ a = dynamic_cast<LoginCpp::App^>(Application::Current);
nextResult = LoginViaRerequest(parameters); Windows::UI::Xaml::Controls::Frame^ f = a->CreateRootFrame();
} f->Navigate(MainPage::typeid);
}
return nextResult; else
}) {
.then([=](FBResult^ loginResult) create_task(sess->LoginAsync(BuildPermissions())).then([=](FBResult^ result)
{ {
task<FBResult^> finalResult = 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
return loginResult; // 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 (loginResult->Succeeded) if (WasAppPermissionRemovedByUser(result))
{ {
if (!DidGetAllRequestedPermissions()) LogoutAndRetry();
{ }
finalResult = LoginViaRerequest(parameters); else if (ShouldRerequest(result))
} {
} // Login call has to happen on UI thread, so circle back around to it
CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
return finalResult; Windows::UI::Core::CoreDispatcherPriority::Normal,
}) ref new Windows::UI::Core::DispatchedHandler([=]()
.then([=](FBResult^ finalResult) {
{ TryRerequest(FALSE);
if (finalResult->Succeeded) }));
{ }
NavigateToOptionsPage(); 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 namespace LoginCpp
{ {
/// <summary> /// <summary>
/// An empty page that can be used on its own or navigated to within a Frame. /// An empty page that can be used on its own or navigated to within a Frame.
/// </summary> /// </summary>
public ref class MainPage sealed public ref class MainPage sealed
{ {
public: public:
MainPage(); MainPage();
protected:
virtual void OnNavigatedTo(
Windows::UI::Xaml::Navigation::NavigationEventArgs^ e
) override;
private: private:
void StartLogin( void MainPage::SetSessionAppIds(
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
); );
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"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <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')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

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

@ -32,6 +32,8 @@ using Windows.UI.Xaml.Navigation;
using Facebook; using Facebook;
using Windows.Globalization; 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 // The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
@ -45,11 +47,14 @@ namespace LoginCs
public MainPage() public MainPage()
{ {
this.InitializeComponent(); 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", "public_profile",
"email", "email",
@ -57,39 +62,55 @@ namespace LoginCs
"publish_actions" "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++) for (uint i = 0; i < requested_permissions.Length; i++)
{ {
if (i > 0) perms.Add(requested_permissions[i]);
{
permissions += ",";
}
permissions += 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; 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++) 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++; grantedCount++;
} }
@ -98,49 +119,53 @@ namespace LoginCs
if (grantedCount == requested_permissions.Length) if (grantedCount == requested_permissions.Length)
{ {
gotPermissions = true; success = true;
} }
} }
return gotPermissions; return success;
} }
private async void LoginToFB() bool WasAppPermissionRemovedByUser(
FBResult Result
)
{ {
Uri endURI = return ((Result != null) &&
WebAuthenticationBroker.GetCurrentApplicationCallbackUri(); (!Result.Succeeded) &&
string uriString = endURI.ToString(); (Result.ErrorInfo.Code == (int)Facebook.ErrorCode.ErrorCodeOauthException));
PropertySet parameters = new PropertySet(); }
parameters.Add(new KeyValuePair<String, Object>("scope", bool ShouldRerequest(
BuildPermissionsString())); FBResult Result
)
{
return ((Result != null) &&
Result.Succeeded &&
!DidGetAllRequestedPermissions());
}
FBResult result = await FBSession.ActiveSession.LoginAsync(parameters); async Task TryRerequest(
if ((!result.Succeeded) && bool Retry
(((ErrorCode)result.ErrorInfo.Code == ErrorCode.ErrorCodeOauthException) && )
((ErrorSubcode)result.ErrorInfo.Subcode == ErrorSubcode.ErrorSubcodeSessionInvalidated))) {
{ // If we're logged out, the session has cleared the FB and Windows app IDs,
parameters.Add(new KeyValuePair<String, Object>("auth_type", "rerequest")); // so they need to be set again. We load these IDs via the ResourceLoader
result = await FBSession.ActiveSession.LoginAsync(parameters); // 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 (result.Succeeded)
{ {
if (DidGetRequestedPermissions()) if (Retry && (!DidGetAllRequestedPermissions()))
{ {
Frame.Navigate(typeof(UserInfo)); await TryRerequest(false);
} }
else else
{ {
if (!parameters.ContainsKey("auth_type")) //Navigate back to same page, to clear out logged in info.
{ App.RootFrame.Navigate(typeof(UserInfo));
parameters.Add(new KeyValuePair<String, Object>("auth_type", "rerequest"));
}
result = await FBSession.ActiveSession.LoginAsync(parameters);
if (result.Succeeded)
{
Frame.Navigate(typeof(UserInfo));
}
} }
} }
} }
@ -194,7 +219,27 @@ namespace LoginCs
else else
{ {
LoginButton.Content = "Logout"; 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.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime; using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.ApplicationModel.Resources; using Windows.ApplicationModel.Resources;
using Windows.Foundation; using Windows.Foundation;
using Windows.Foundation.Collections; using Windows.Foundation.Collections;
@ -41,45 +42,133 @@ namespace LoginCs
/// </summary> /// </summary>
public sealed partial class MainPage : Page public sealed partial class MainPage : Page
{ {
const string FBAppIDName = "FBApplicationId"; const string FBAppIDName = "FBApplicationId";
const string FBPhoneAppIDName = "FBWinPhoneAppId"; const string FBPhoneAppIDName = "FBWinPhoneAppId";
const string PermissionGranted = "granted";
readonly string[] requested_permissions =
{
"public_profile",
"user_friends",
"user_likes",
"user_groups",
"user_location"
};
public MainPage() public MainPage()
{ {
this.InitializeComponent(); this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required; this.NavigationCacheMode = NavigationCacheMode.Required;
SetSessionAppIds();
} }
public async void StartLogin( void SetSessionAppIds(
) )
{ {
FBSession s = FBSession.ActiveSession; FBSession s = FBSession.ActiveSession;
// Assumes the Facebook App ID and Windows Phone Store ID have been // Assumes the Facebook App ID and Windows Phone Store ID have been saved
// saved in the default resource file. // in the default resource file.
ResourceLoader rl = ResourceLoader.GetForCurrentView(); ResourceLoader rl = ResourceLoader.GetForCurrentView();
String appId = rl.GetString(FBAppIDName); String appId = rl.GetString(FBAppIDName);
String winAppId = rl.GetString(FBPhoneAppIDName); String winAppId = rl.GetString(FBPhoneAppIDName);
// IDs are both sent to FB app, so it can validate us. // IDs are both sent to FB app, so it can validate us.
s.FBAppId = appId; s.FBAppId = appId;
s.WinAppId = winAppId; s.WinAppId = winAppId;
}
// These are the default permissions, needed to retrieve user info. FBPermissions BuildPermissions(
//s.AddPermission("public_profile"); )
//s.AddPermission("user_friends"); {
//s.AddPermission("user_likes"); FBPermissions result = new FBPermissions();
List<string> perms = new List<string>();
PropertySet parameters = new PropertySet(); for (uint i = 0; i < requested_permissions.Length; i++)
parameters.Add( {
new KeyValuePair<string, object>("scope", perms.Add(requested_permissions[i]);
"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. result.Values = perms;
FBResult result = await s.LoginAsync();
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> /// <summary>
@ -127,7 +216,27 @@ namespace LoginCs
else else
{ {
LoginButton.Content = "Logout"; 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));
}
} }
} }
} }