'Blazor WASM redirect to login when not authenticated - Don't show layout

I have a Blazor WASM having 2 layouts:

  1. MainLayout
  2. LoginLayout

My main Index file has an Authorized attribute

@page "/"
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@attribute [Authorize]

When its not authorized is being redirected to "auth/login" which uses a different layout (LoginLayout) where I have a simple login page.

The problem im facing is that when I access the application I can see for a second the MainLayout (header, navigation left menu, footer) and then I see my blank screen with my login.

This means that because Index is the main route and uses MainLayout, it takes about 1 second to validate and do the redirect to my Login page and thats why the Layout issue.

Is there a way to do the redirect before the MainLayout is rendered in the page? Or a way to not show the Layout HTML if the user is not authenticated?



Solution 1:[1]

Try the following code... I tested it superficially in WebAssembly hosted with individual authentication and it seems fine. If the user is not authenticated, and the Index component is annotated with the Authorize attribute, he's redirected to the Login page, without seeing the MainLayout.

Change the code in MainLayout.razor to the following:

@inherits LayoutComponentBase

<AuthorizeView>
    <Authorized>
        <div class="sidebar">
            <NavMenu />
        </div>

        <div class="main">
            <div class="top-row px-4 auth">
                <LoginDisplay />
                <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
            </div>

            <div class="content px-4">
                @Body
            </div>
        </div>

    </Authorized>
    <NotAuthorized>
        <div class="main">
            <div class="content px-4">
                @Body
            </div>
        </div>
   </NotAuthorized>
</AuthorizeView> 

Test the code above, and see if it does satisfy your expectations, then model you things accordingly. Note that your Login component should be decorated with the @layout directive, so that Blazor will display the Login component within your custom layout.

Model your custom layout after the DEFAULT MainLayout...Remove the unnecessary parts, and add your own as needed.

This: @inherits LayoutComponentBase

And this:

   <div class="main">
                <div class="content px-4">
                    @Body
                </div>
   </div> 

are a must...

Solution 2:[2]

You can just create another empty layout and use it

    @inherits LayoutComponentBase
    <div>
       @Body
     </div>

in the login page

    @layout EmptyLayout
     <div class="container">
       <EditForm class="login-form" Model="model" OnValidSubmit="LoginSubmit">
        
        ...

      <button type="submit" class="btn btn-primary">?????</button>
      </EditForm>
    </div>

Redirect to Login Component

    @inject NavigationManager navigationManager

    @code {
    protected override void OnInitialized()
    {
    navigationManager.NavigateTo("/system/login");
    }
 }

App.razor

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

Solution 3:[3]

You can remove

DefaultLayout="@typeof(MainLayout)

from AuthorizeRouteView tag in App.razor file:

App.razor:

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

, but you must put

@layout MainLayout

in all authorized page

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 enet
Solution 2 user9463137
Solution 3 hamid reza shahshahani