5

For my Xamarin.Forms app, I am looking for a way to check if a user has the right role/authentication status to access a page. I know Angular has route guards that can be reused for different routes to check for an authentication status. Is there something similar in Xamarin.Forms?

  • 1
    You can define a property IsLogged and bind pages property IsVisible that requires user to be logged to that property. Shell will hide anypage that has IsVisible="false" – Cfun Dec 07 '20 at 17:18
  • @Cfun ah great! Is it also possible to still show the page, but redirect based on this login property? I have for example a account page, where you can view your profile. But only if your logged in. Because i want to still show the icon, but redirect conditionally to the login/account page. – Kevin van Schaijk Dec 07 '20 at 17:23
  • sure you can do that at the end you can structure your app as you want, depending on your app structure if you provide a specific case with some details i would provide an example highlighting this. – Cfun Dec 07 '20 at 17:27

1 Answers1

9

Here is an example showing how you can control the visibility or navigation to your pages based on the login status of the user.

By default Shell will always displays initially the first element defined in AppShell.xaml, in this case it will be Login.xaml page.

In the below example "Page3" will be visible initially because by default (Isvisible=true), while "Page2" it will only be visible when the bindable property IsLogged is true.

  • You can handle any logic when user Log in/Log out in the IsLogged_PropertyChanged() event.

  • If you want several/specific or page based roles you can always create/define/design yours, use them in bindings, raise and use their property changed event to execute actions.


With FlyoutItem

AppShell.xaml

<Shell Shell.FlyoutBehavior="Disabled"..>
   <FlyoutItem FlyoutDisplayOptions="AsMultipleItems">
        <Tab>
            <ShellContent Title="Login" Route="Login">
                <local:Login />
            </ShellContent>

            <ShellContent Title="Page2" Route="Page2"
                ContentTemplate="{DataTemplate local:Page2}"
                IsVisible="{Binding IsLogged}"/>

            <ShellContent Title="Page3" Route="Page3"
                ContentTemplate="{DataTemplate local:Page3}"/>
        </Tab>
    </FlyoutItem>

AppShell.xaml.cs

public bool IsLogged
{
    get => (bool)GetValue(IsLoggedProperty);
    set => SetValue(IsLoggedProperty, value);
}

public static readonly BindableProperty IsLoggedProperty =
    BindableProperty.Create("IsLogged", typeof(bool), typeof(AppShell), false, propertyChanged: IsLogged_PropertyChanged);

private static void IsLogged_PropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
//handle log in/log out event
    if ((bool) newValue)
       //user just logged in logic
    else
      //user just logged out logic
}

Login.xaml

<StackLayout>
    <Label
        FontSize="45"
        HorizontalOptions="FillAndExpand"
        Text="Login Page" />
    <Button Clicked="Button_Clicked" Text="Log In" />
</StackLayout>

Login.xaml.cs

private async void Button_Clicked(object sender, System.EventArgs e)
{
    IsVisible = false;                          //hide login page
    //Trigger the binding to show pages previously hidden
    (Shell.Current as AppShell).IsLogged = true;
    await Shell.Current.GoToAsync("//Page2");   //navigate to main page (next after log)
                                               //Enable the flyout: hamburger button
    Shell.Current.FlyoutBehavior = FlyoutBehavior.Flyout;  
}

Same thing with Tabs

In this example "Symbols" bottom tab won't be visible the same for upper tab "B" that belongs to bottom tab "Letters" until the user log-in, the remaining bottoms tabs will be visible initially.

AppShell.xaml

<TabBar>
    <ShellContent Title="Login" Route="Login">
        <local:Login />
    </ShellContent>

    <Tab Title="Letters">
        <ShellContent
            Title="A"
            ContentTemplate="{DataTemplate local:Page1}"
            Route="Page1" />

        <ShellContent
            Title="B"
            ContentTemplate="{DataTemplate local:Page2}"
            IsVisible="{Binding IsLogged}"
            Route="Page2" />

        <ShellContent
            Title="C"
            ContentTemplate="{DataTemplate local:Page3}"
            Route="Page3" />
    </Tab>

    <Tab Title="Digits">
        <ShellContent
            Title="100"
            ContentTemplate="{DataTemplate local:Page4}"
            Route="Page4" />
    </Tab>

    <Tab Title="Symbols" IsVisible="{Binding IsLogged}">
        <ShellContent
            Title="!"
            ContentTemplate="{DataTemplate local:Page5}"
            Route="Page5" />
    </Tab>
</TabBar>

Edit

You may also want to add Shell.NavBarIsVisible="False" and Shell.TabBarIsVisible="false" in the Tabbar case, to the LoginPage to respectively hide the navigation bar and hide the bottom tab bar.

Cfun
  • 8,442
  • 4
  • 30
  • 62
  • 1
    Thanks! I think i can build my usecase with this example. – Kevin van Schaijk Dec 07 '20 at 21:05
  • Where does AppShell comes from ? Is that your main page or is it something that should be present in an xamarin app ? – GuidoG Dec 27 '21 at 07:01
  • @GuidoG yes it is the MainPage, also name it as you like as long as you subclass [Shell](https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/create) – Cfun Dec 27 '21 at 10:42
  • If one intends to change tabs state dynamically at runtime expect that appearance tracker will be called before native views are updated, so when you detect a difference between forms tabs count and native views count queue an appearance update 50msecs after. – Nick Kovalsky Mar 17 '22 at 05:25
  • This makes no sense whatsoever (I'm new to MAUI so forgive me) My app has a couple of pages to get through before you get to the Flyout page. Are you saying every page of your app is done in the Shell? Seems crazy. I like to have each page look after itself with both markup and code. Why can't I have the flyout in a page of its own ? – djack109 Sep 23 '22 at 19:21