ZBoyet
ZBoyet

Reputation: 51

Disable Blazor "Authorizing" splash screen on OIDC authorization where not needed

I have a blazor wasm application with prerendering and auth via oidc through an IdentityServer4. I pretty much have it all set up and things are looking good. The problem I have is with the oidc package from Microsoft.AspNetCore.Components.WebAssembly.Authentication there seems to be a mandatory "Authorizing" splash screen that I cannot disable. With prerendering on a page that does not need authentication this means that a user will see the data on the page and then after a second or two it will be replaced by a full screen authenticating screen and then the data on the page will come back. The UX on this is so terrible I am thinking I must have something setup wrong and that this cannot be the only way it works but for the life of me I cannot find a solution to this on my own or via google...

App.razor

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

The problem here is that I cannot simply remove the Authorizing tag. If I do a default page is shown anyway. I would really like it if I could get it to only show that splash screen if the page had an "@attribute [Authorize]" attribute or at least did not have a "@attribute [AllowAnonymous]".

Have I run up against a limitation of the package?

Thanks for any guidance on this.

Also might be useful but probably not. The service is setup like so.

builder.Services.AddOidcAuthentication<RemoteAuthenticationState, MyRemoteUserAccount>(options =>
{
    builder.Configuration.Bind("OidcProviderOptions", options.ProviderOptions);

    options.UserOptions.ScopeClaim = JwtClaimTypes.Scope;
    options.UserOptions.RoleClaim = JwtClaimTypes.Role;
})
.AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, MyRemoteUserAccount, MyUserFactory>();

Upvotes: 3

Views: 1675

Answers (2)

Felicity Winter
Felicity Winter

Reputation: 16

I think you'll find the answer you're looking for in another thread here.

I also went searching only to discover just how easy the solution was:

<MudThemeProvider/>
<MudDialogProvider/>
<MudSnackbarProvider/>
<CascadingAuthenticationState>
    <Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
        <Found Context="routeData">
            <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
                <Authorizing>
                    @* YOUR CODE HERE *@
                </Authorizing>
                <NotAuthorized>
                    @if (!context.User.Identity.IsAuthenticated)
                    {
                        <RedirectToLogin />
                    }
                    else
                    {
                        <p>You know, I have no idea how you got here but this is not a place I let people into!</p>
                    }
                </NotAuthorized>
            </AuthorizeRouteView>
        </Found>
        <NotFound>
            <LayoutView Layout="@typeof(MainLayout)">
                <p>Sorry, there's nothing at this address, well, yet anyway!</p>
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>

Upvotes: -1

ZBoyet
ZBoyet

Reputation: 51

Ok, I think I have come up with an acceptable solution. It is a little fiddly but gets the job done.

I have abandoned any attempt at displaying auth state at the root level.

My App.razor now looks like this

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

Then in the root template of the app I have something like this

@if(AllowAnonymous)
{
    @RootBody
}
else
{
    <AuthorizeView>
        <NotAuthorized>
            <p>Not authorized to read page contents.</p>
        </NotAuthorized>
        <Authorizing>
            <p>Authorizing.</p>
        </Authorizing>
        <Authorized>
            @RootBody
        </Authorized>
    </AuthorizeView>
}

If I need to disable the auth status I pass AllowAnonymous=true to the component. I would like to eventually make this automatic depending on the parent page's authorization attribute but this works for now.

Upvotes: 2

Related Questions