Autenticação usando a conta do Facebook, Google e Microsoft numa app de WP8.0

Uma vez que as classes relacionadas com a autenticação estão criadas, agora passamos para a parte da interface com o utilizador e para isso iremos criar o LoginViewModel e a página LoginView.

A classe LoginViewModel será:

public class LoginViewModel : ViewModelBase 
    { 
        private readonly ILogManager _logManager; 
        private readonly IMessageBoxService _messageBox; 
        private readonly INavigationService _navigationService; 
        private readonly ISessionService _sessionService; 
        private bool _inProgress; 
         
        public LoginViewModel(INavigationService navigationService, 
            ISessionService sessionService, 
            IMessageBoxService messageBox, 
            ILogManager logManager) 
        { 
            _navigationService = navigationService; 
            _sessionService = sessionService; 
            _messageBox = messageBox; 
            _logManager = logManager; 
            LoginCommand = new RelayCommand(LoginAction); 
        } 
 
        public bool InProgress 
        { 
            get { return _inProgress; } 
            set { Set(() => InProgress, ref _inProgress, value); } 
        } 
 
        public ICommand LoginCommand { get; private set; } 
       
        private async void LoginAction(string provider) 
        { 
            Exception exception = null; 
            bool isToShowMessage = false; 
            try 
            { 
                InProgress = true; 
                var auth = await _sessionService.LoginAsync(provider); 
                if (!auth) 
                { 
                    await _messageBox.ShowAsync(AppResources.LoginView_LoginNotAllowed_Message, 
                        AppResources.MessageBox_Title, 
                        new List 
                    { 
                        AppResources.Button_OK 
                    }); 
                } 
                else 
                { 
                    _navigationService.NavigateTo(new Uri(Constants.MainView, UriKind.Relative)); 
                } 
 
                InProgress = false; 
            } 
            catch (InvalidOperationException e) 
            { 
                InProgress = false; 
                isToShowMessage = true; 
            } 
            catch (Exception ex) 
            { 
                exception = ex; 
            } 
            if (isToShowMessage) 
            { 
                await _messageBox.ShowAsync(AppResources.LoginView_AuthFail, AppResources.ApplicationTitle, new List { AppResources.Button_OK }); 
            } 
            if (exception != null) 
            { 
                await _logManager.LogAsync(exception); 
            } 
        } 
    }

De salientar que no método LoginAction o parâmetro recebido é o valor do CommandParameter definido no LoginCommand (isto é definido na UI).

A página LoginView.xaml será:

<phone:PhoneApplicationPage x:Class="AuthenticationSample.WP80.Views.LoginView"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:Command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP8" 
      xmlns:controls="clr-namespace:Facebook.Client.Controls;assembly=Facebook.Client" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" 
      xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" 
      xmlns:converters="clr-namespace:Cimbalino.Phone.Toolkit.Converters;assembly=Cimbalino.Phone.Toolkit" 
      Orientation="Portrait" 
      SupportedOrientations="Portrait" 
      shell:SystemTray.IsVisible="True" 
      mc:Ignorable="d"> 
   <phone:PhoneApplicationPage.DataContext> 
      <Binding Mode="OneWay" 
            Path="LoginViewModel" 
            Source="{StaticResource Locator}" /> 
   </phone:PhoneApplicationPage.DataContext> 
   <phone:PhoneApplicationPage.Resources> 
      <converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/> 
   </phone:PhoneApplicationPage.Resources> 
   <phone:PhoneApplicationPage.FontFamily> 
      <StaticResource ResourceKey="PhoneFontFamilyNormal" /> 
   </phone:PhoneApplicationPage.FontFamily> 
   <phone:PhoneApplicationPage.FontSize> 
      <StaticResource ResourceKey="PhoneFontSizeNormal" /> 
   </phone:PhoneApplicationPage.FontSize> 
   <phone:PhoneApplicationPage.Foreground> 
      <StaticResource ResourceKey="PhoneForegroundBrush" /> 
   </phone:PhoneApplicationPage.Foreground> 
   <!--  LayoutRoot is the root grid where all page content is placed  --> 
   <Grid x:Name="LayoutRoot" Background="Transparent"> 
      <Grid.RowDefinitions> 
         <RowDefinition Height="Auto" /> 
         <RowDefinition Height="*" /> 
      </Grid.RowDefinitions> 
 
      <!--  TitlePanel contains the name of the application and page title  --> 
      <StackPanel x:Name="TitlePanel" 
            Grid.Row="0" 
            Margin="12,17,0,28"> 
         <TextBlock Margin="12,0" 
               Style="{StaticResource PhoneTextNormalStyle}" 
               Text="{Binding LocalizedResources.ApplicationTitle, 
                     Mode=OneWay, 
                     Source={StaticResource LocalizedStrings}}" /> 
         <TextBlock Margin="9,-7,0,0" 
               Style="{StaticResource PhoneTextTitle1Style}" 
               Text="{Binding LocalizedResources.LoginView_Title, 
                     Mode=OneWay, 
                     Source={StaticResource LocalizedStrings}}" /> 
      </StackPanel> 
 
      <!--  ContentPanel - place additional content here  --> 
      <Grid x:Name="ContentPanel" 
            Grid.Row="1" 
            Margin="24,0,0,-40"> 
         <Grid.RowDefinitions> 
            <RowDefinition Height="Auto" /> 
            <RowDefinition Height="Auto" /> 
            <RowDefinition Height="Auto" /> 
            <RowDefinition Height="Auto" /> 
            <RowDefinition Height="Auto" /> 
         </Grid.RowDefinitions> 
         <TextBlock Grid.Row="0" 
               Style="{StaticResource PhoneTextTitle2Style}" 
               Text="{Binding LocalizedResources.LoginView_UserAccount, 
                     Mode=OneWay, 
                     Source={StaticResource LocalizedStrings}}" /> 
         <Button Grid.Row="1" 
               Margin="10" 
               Command="{Binding LoginCommand}" 
               CommandParameter="facebook" 
               Content="Facebook" /> 
         <Button Grid.Row="2" 
               Margin="10" 
               Command="{Binding LoginCommand}" 
               CommandParameter="microsoft" 
               Content="Microsoft" /> 
         <Button Grid.Row="3" 
               Margin="10" 
               Command="{Binding LoginCommand}" 
               CommandParameter="google" 
               Content="Google" /> 
      </Grid> 
      <Grid Visibility="{Binding InProgress, Converter={StaticResource BooleanToVisibilityConverter}}" 
            Grid.Row="0" 
            Grid.RowSpan="2"> 
         <Rectangle  
               Fill="Black" 
               Opacity="0.75" /> 
         <TextBlock  
               HorizontalAlignment="Center" 
               VerticalAlignment="Center" 
               Text="{Binding LocalizedResources.LoginView_AuthMessage, 
                     Mode=OneWay, 
                     Source={StaticResource LocalizedStrings}}" /> 
         <ProgressBar IsIndeterminate="True" IsEnabled="True" Margin="0,60,0,0"/> 
      </Grid> 

   </Grid> 
</phone:PhoneApplicationPage>

E o resultado final será:

O código fonte do exemplo apresentado pode ser obtido aqui.

Em conclusão, podemos verificar que é extremamente simples criar uma aplicação que use autenticação usando a conta Facebook, Google ou Microsoft, facilitando assim o desenvolvimento da aplicação, pelo facto de não ter necessidade de criar uma autenticação personalizada e por outro lado o utilizador poderá usar a conta que à partida já tem, evitando assim criar mais uma conta nova.

Publicado na edição 46 (PDF) da Revista PROGRAMAR.