In order to add sign in capabilities to our app, we need to create a new Page and a new ViewModel. The ViewModel will be pretty straightforward, containing just a single command that handles signing in to Facebook via the IAuthService
, passing the received Facebook token to the Azure backend service through the ITripLogDataService
, and then storing the Azure access token in local settings.
There are a couple of ways to tap into the local storage platform-specific APIs to store settings. One way is to roll your own, similar to how we did the location service: creating a core interface that is implemented uniquely per platform. Another alternative is to leverage a plugin or other third party component that has been published. In this section, we will use a plugin called Settings Plugin for Xamarin and Windows, available on NuGet as Xam.Plugins.Settings by James Montemagno. There are also several other types of plugins made available by members of the Xamarin community at https://github.com/xamarin/plugins.
BaseViewModel
named SignInViewModel
in the ViewModels folder in the core library:public class SignInViewModel : BaseViewModel { }
SignInViewModel
with a constructor that takes in an INavService
, IAuthService
, and ITripLogDataService
parameter:public class SignInViewModel : BaseViewModel { readonly IAuthService _authService; readonly ITripLogDataService _tripLogService; public SignInViewModel (INavService navService, IAuthService authService, ITripLogDataService tripLogService) :base(navService) { _authService = authService; _tripLogService = tripLogService; } }
ICommand
property named SignInCommand
to the SignInViewModel
along with its execute Action
:public class SignInViewModel : BaseViewModel { // ... ICommand _signInCommand; public ICommand SignInCommand { get { return _signInCommand ?? (_signInCommand = new Command (async () => await ExecuteSignInCommand ())); } } async Task ExecuteSignInCommand() { // TODO: Update with your Facebook Client Id await _authService.SignInAsync ( "YOUR_FACEBOOK_CLIENTID", new Uri ("https://m.facebook.com/dialog/oauth"), new Uri ("https://triplog.azurewebsites.net/.auth/login/facebook/callback"), tokenCallback: async t => { // Use Facebook token to get Azure auth token var response = await _tripLogService.GetAuthTokenAsync ("facebook", t); // Save auth token in local settings Helpers.Settings.TripLogApiAuthToken = response.AuthenticationToken; // Navigate to Main await NavService.NavigateTo<MainViewModel> (); await NavService.RemoveLastView (); }, errorCallback: e => { // TODO: Handle invalid authentication here }); } }
BaseViewModel
Init
method to clear the navigation back stack anytime the SignInViewModel
is loaded:public override async Task Init (){await NavService.ClearBackStack ();}
TripLogCoreModule
to add SignInViewModel
to the IoC container:public class TripLogCoreModule : NinjectModule
{
public override void Load ()
{
// ViewModels
Bind<SignInViewModel> ().ToSelf();
Bind<MainViewModel> ().ToSelf ();
Bind<DetailViewModel> ().ToSelf ();
Bind<NewEntryViewModel> ().ToSelf ();
// ...
}
}
TripLogCoreModule
to account for the updated TripLogApiDataService
constructor and pass in the auth token stored in local settings:var tripLogService = new TripLogApiDataService (
new Uri("https://<your-service-name>.azurewebsites.net"),
Helpers.Settings.TripLogApiAuthToken);
Next, we need to create the actual sign in page, which we will use with the SignInViewModel
as its data context.
Views
folder in the core library named SignInPage
:public class SignInPage : ContentPage { }
SignInPage
to add a button that is bound to SignInViewModel
's SignInCommand
:public class SignInPage : ContentPage { public SignInPage () { Padding = 20; var facebookButton = new Button { BackgroundColor = Color.FromHex("#455c9f"), TextColor = Color.White, Text = "Sign in with Facebook" }; facebookButton.SetBinding (Button.CommandProperty, "SignInCommand"); var mainLayout = new StackLayout { VerticalOptions = LayoutOptions.Center, Children = { facebookButton } }; Content = mainLayout; } }
SignInPage
and SignInViewModel
mapping in the navigation service in the TripLogNavModule
:public class TripLogNavModule : NinjectModule
{
// ...
public override void Load ()
{
var navService = new XamarinFormsNavService ();
navService.XamarinFormsNav = _xfNav;
// Register view mappings
navService.RegisterViewMapping (typeof(SignInViewModel), typeof(SignInPage));
navService.RegisterViewMapping (typeof(MainViewModel), typeof(MainPage));
navService.RegisterViewMapping (typeof(DetailViewModel), typeof(DetailPage));
navService.RegisterViewMapping (typeof(NewEntryViewModel), typeof(NewEntryPage));
Bind<INavService> ().ToMethod (x => navService)
.InSingletonScope ();
}
}
Finally, we need to make two minor adjustments to the app so that users will go directly to the SignInPage
if an auth token does not exist in local settings.
bool
property to the App
class that indicates if an auth token is present by checking the Settings
helper class:public bool IsSignedIn { get { return !string.IsNullOrWhiteSpace (Helpers.Settings.TripLogApiAuthToken); } }
Init
method of the MainViewModel
to forward the user to the SignInViewModel
if the IsSignedIn
property is false:public override async Task Init () { if (!((App)Application.Current).IsSignedIn) await NavService.NavigateTo<SignInViewModel> (); else LoadEntries (); }
Now, when the app is launched for the first time and an auth token is not present in the local settings, you will see the SignInPage
. Clicking the sign in button will launch the Xamarin.Auth dialog prompting for Facebook credentials and permission to grant access to the TripLog app, as shown in the following screenshots. Upon successfully authenticating with Facebook, you should be automatically brought to the MainPage
and the list of the Entry
objects will be loaded from the API.
3.149.236.27