Home > Net >  MAUI AAD Authentication ClaimsPrincipal with IsAuthenticated always false
MAUI AAD Authentication ClaimsPrincipal with IsAuthenticated always false

Time:11-01

I have a MAUI app running on localhost and when you start the app, it triggers microsoft login, after the user sucessfull login I catch the ClaimsPrincipal and IsAuthenticated is always false. According to my Main.razor component if the user is not Authenticated it calls the RedirectToLogin Component again and I don't know how to Authorize my logged in user in the app so it might have somethin to do with the IsAuthenticated being false.

I have seen some solutions and they say you have to build ClaimsPrincipal passin the authentication type as parameter to the ClaimsIdentity like this:

new ClaimsPrincipal(new Identity("something"))

The problem is that I get already the ClaimsPrincipal from AAD só I dont know what I should do because I have no way to see the AAD because it is taken care by other team.

This is my Main.razor component:

<Router AppAssembly="@typeof(Main).Assembly">
    <Found Context="routeData">
        <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
            <Authorizing>
                Authorizing...
            </Authorizing>
            <NotAuthorized>
                <RedirectToLogin />
            </NotAuthorized>
        </AuthorizeRouteView>
    </Found>
    <NotFound>
        <CascadingAuthenticationState>
            <LayoutView Layout="@typeof(MainLayout)">
                <p role="alert">Sorry, there's nothing at this address.</p>
            </LayoutView>
        </CascadingAuthenticationState>
    </NotFound>
</Router>

This is RedirectToLogin component:

@using Microsoft.AspNetCore.Components.Authorization
@using OfficeManagerApp.Areas.Services.Implementations
@inject AuthenticationStateProvider AuthenticationStateProvider
@inject NavigationManager NavigationManager


<div ><span>Redirecting...</span></div>

@code {
    
    protected override async Task OnInitializedAsync()
    {
        await ((ExternalAuthStateProvider)AuthenticationStateProvider)
            .LogInAsync();            
    
        NavigationManager.NavigateTo("/", forceLoad: true);
    }
}

and here is where I have the break point to see the CLaimsPrincipal inside the ExternalAuthStateProvider class:

ExternalAuthStateProvider

Here are the tutorials I followed for this.

PlatformService tutorial

ExternalAuthStateProvider tutorial

I also have a solution using just the PlatformService tutorial with the same problem.

CodePudding user response:

After a while I found the solution!

Basically you receive a ClaimsPrincipal from AAD but you have to create your own ClaimsPrincipal inside the app using the claims from the AAD ClaimsPrincipal.

In ExternalAuthStateProvider.cs, LoginWithExternalProviderAsync() method I did the following:

        private async Task<ClaimsPrincipal> LoginWithExternalProviderAsync()
        {
            var authenticationResult = await _platformService.GetAuthenticationResult();            

            var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity(authenticationResult.ClaimsPrincipal.Claims, "Basic"));            

            return await Task.FromResult(authenticatedUser);            
        }

You just need to do this and then it works!!

Extra -----------

To improve the flow login logout, I created a LoginPage.razor:

@page "/login"
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@using OfficeManagerApp.Areas.Services.Implementations
@attribute [AllowAnonymous]

@inject AuthenticationStateProvider AuthenticationStateProvider
@inject NavigationManager NavigationManager

<button @onclick="Login">Log in</button>

@code
{
    public async Task Login()
    {
        await ((ExternalAuthStateProvider)AuthenticationStateProvider)
            .LogInAsync();

        NavigationManager.NavigateTo("/");
    }
}

Changed the RedirectToLogin,razor:

@inject NavigationManager NavigationManager


<div ><span>Redirecting...</span></div>

@code {

    protected override void OnInitialized()
    {        
        NavigationManager.NavigateTo("/login");
    }
}

And added a logout method:

    private void Logout(){
        ((ExternalAuthStateProvider)AuthenticationStateProvider)
            .Logout();  
    }

Also did some changes to my Main.razor:

<CascadingAuthenticationState>
    <Router AppAssembly="@typeof(Main).Assembly">
        <Found Context="routeData">
            <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
                <Authorizing>
                    Authorizing...
                </Authorizing>
                <NotAuthorized>
                    @if (!context.User.Identity.IsAuthenticated)
                    {
                        <RedirectToLogin />
                    }
                    else
                    {
                        <p>You are not authorized to access this resource.</p>
                    }                   
                </NotAuthorized>
            </AuthorizeRouteView>
        </Found>
        <NotFound>      
            <LayoutView Layout="@typeof(MainLayout)">
                <p role="alert">Sorry, there's nothing at this address.</p>
            </LayoutView>       
        </NotFound>
    </Router>
</CascadingAuthenticationState>

Note don't forget to add to your _Imports.razor:

@using Microsoft.AspNetCore.Components.Authorization
  • Related