How to implement automatic login in Xamarin?

389 views Asked by At

I am implementing an application in Xamarin with a login functionality. I am using Xamarin SecureStorage to store my username and password in Keychain. I am using Prism to segue between my pages.

I have an AuthenticationService that handles all saving and storing keychain data with SecureStorage. In my App.Xaml, I have a PubSubEvent below that handles when the user is authenticated or not.

   var result = await NavigationService.NavigateAsync("/MainPage?title=Welcome");

   if (!result.Success)
   {
        Console.WriteLine("Error {0}", result.Exception);
        logger.Report(result.Exception, new Dictionary<string, string> { { "navigationPath", "/MainPage" } });
                //MainPage = result.CreateErrorPage();
        System.Diagnostics.Debugger.Break();
   }

In my LoginPageViewModel I have the following binding based on my login button.

   private async Task OnLoginUserCommandExecutedAsync()
    {
        try
        {
            MyPrivateSession response = new MyPrivateSession();

            //Username/Password text is valid
            response = await _authenticationService.LoginAsync(UserLogin);

            if (!response.IsValidUser)
            {
                await PageDialogService.DisplayAlertAsync("", "Login Unsuccessful - Invalid User Id or Password", "Ok");
            }
        }

        catch (AuthenticationException authEx)
        {
            await PageDialogService.DisplayAlertAsync("Error", authEx.Message, "Ok");
        }

        catch (Exception e)
        {
            Debugger.Break();
            Logger.Log(e.Message, Category.Exception, Priority.Medium);
            await PageDialogService.DisplayAlertAsync("Fatal Error", e.Message, "Ok");
        }
    }

Also in my LoginPageViewModel, I have the following code in onNavigatedTo to get saved login from SecureStorage

   public override async void OnNavigatedTo(INavigationParameters parameters)
        {
            // Determine if there is a preferred account to use in cases where the user is logged out and sent directly to the login
            // in this case the AssumedLogin isn't defined.
            if (_authenticationService.AssumedLogin is null)
            {
                await _authenticationService.AssumeUserPriorToLogin();
                if (!(_authenticationService.AssumedLogin is null))
                {

                    UserLogin.Username = _authenticationService.AssumedLogin.Username;
                    UserLogin.Password = _authenticationService.AssumedLogin.Properties["password"];

                    //Segues to VIN Utilities
                    await OnLoginUserCommandExecutedAsync();

                }
            }
        }

In my AuthenticationService, I have this at the end of my logic after accessing username and password from SecureStorage

var user = GetCurrentUser();
                    _container.UseInstance(user);

                    //Publish User Authenticated Event
                    _eventAggregator.GetEvent<UserAuthenticatedEvent>().Publish(user);

My problem is when a user manually logs in with the login button, everything works perfectly. However, when I'm adding logic on the LoginPageViewModel's OnNavigatedTo to automatically authenticate user when the user have a saved username and password. It kicks me out of MainPage and back to login page.

One my doubts is that, when I do it automatic login through navigation page, the application is not finished loading yet. The application would log OnNavigatedTo from MainPage first before "Loaded My App" in the AppDelegate. (see below) How can I ensure the iOS initializers finish first before I start segueing to the main page?

   public override bool FinishedLaunching(UIApplication app, NSDictionary options)
    {
        global::Xamarin.Forms.Forms.Init();

        Rg.Plugins.Popup.Popup.Init();
        SlideOverKit.iOS.SlideOverKit.Init();
        SfCheckBoxRenderer.Init();

        Syncfusion.SfCarousel.XForms.iOS.SfCarouselRenderer.Init();

        Console.WriteLine("Loading My App");
        LoadApplication(new App(new IOSInitializer()));
        Console.WriteLine("Loaded My App");

        return base.FinishedLaunching(app, options);
    }

   public class IOSInitializer : IPlatformInitializer
        {
            public void RegisterTypes(IContainerRegistry containerRegistry)
            {

            }
        }

        private void OnUserAuthenticated(IUser user)
        {
             var result = await NavigationService.NavigateAsync("/MainPage");

        if (!result.Success)
        {
            Console.WriteLine("Error {0}", result.Exception);
            //MainPage = result.CreateErrorPage();
            System.Diagnostics.Debugger.Break();
        }
    }
0

There are 0 answers