Aspnetcore: Blazor Server AuthorizeView rendering NotAuthorized before AuthorizationHandler finishes executing

Created on 28 Jul 2020  路  4Comments  路  Source: dotnet/aspnetcore

I'm trying to implement a custom AuthorizationHandler that uses business rules to determine whether or not a user has access to a certain page.

To do that I implemented the following:

CustomMemberHandler.cs

public sealed class CustomMemberHandler: AuthorizationHandler<CustomRequirement, long?>
{
    public override async Task HandleAsync(AuthorizationHandlerContext context)
    {
        if (context.Resource == null || context.Resource is long)
        {
            foreach (var requirement in context.Requirements.OfType<CustomRequirement>())
            {
                await this.HandleRequirementAsync(context, requirement, (long?)context.Resource);
            }
        }
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomRequirement requirement, long? resourceId)
    {
        var userId = context.User.GetUserId();

        if (userId.HasValue && resourceId.HasValue && await <Database Invocation>)
        {
            context.Succeed(requirement);
        }           
        else if (logId.HasValue == false)
        {
            context.Succeed(requirement);
        }
        else
        {
            context.Fail();
        }
    }
}

Startup.cs

services.AddAuthorization(options =>
{
    options.AddPolicy(PolicyConstants.CUSTOM_POLICY, policy =>
    {
        policy.RequireAuthenticatedUser();
        policy.Requirements.Add(new CustomRequirement());
        policy.Build();
    });
});

services.AddTransient<IAuthorizationHandler, CustomMemberHandler>();

And in my component I'm using the following:

BlazorPage.razor

@inherits OwningComponentBase

<AuthorizeView Policy="@PolicyConstants.CUSTOM_POLICY" Resource="@this.Id">
    <Authorized>
        <PageLayout/>
    </Authorized>
    <NotAuthorized>
        <HandleNotAuthorized/>
    </NotAuthorized>
</AuthorizeView>

The HandleNotAuthorized component redirects the user to the AccessDenied page.

I also have an AuthorizeRouteView that's used in the App.razor file.

<CascadingAuthenticationState>
    <Router AppAssembly="@typeof(Program).Assembly">
        <Found Context="routeData">
            <AuthorizeRouteView RouteData="@routeData">
                <NotAuthorized>
                    <HandleNotAuthorized />
                </NotAuthorized>
            </AuthorizeRouteView>
        </Found>
        <NotFound>
            <HandleNotFound />
        </NotFound>
    </Router>
</CascadingAuthenticationState>

What is happening is that the NotAuthorized fragment is being rendered even though the AuthorizationHandler hasn't executed yet (or at least hasn't finished executing). This causes the user to be redirected to the AccessDenied page even though the AuthorizationHandler executes succesfully.

Is this behaviour normal?

Further technical details

  • ASP.NET Core 3.1.4
  • Microsoft Visual Studio Community 2019 Version 16.6.2
.NET Core SDK (reflecting any global.json):
 Version:   3.1.301
 Commit:    7feb845744

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.18363
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\3.1.301\

Host (useful for support):
  Version: 3.1.5
  Commit:  65cd789777

.NET Core SDKs installed:
  3.0.103 [C:\Program Files\dotnet\sdk]
  3.1.102 [C:\Program Files\dotnet\sdk]
  3.1.300 [C:\Program Files\dotnet\sdk]
  3.1.301 [C:\Program Files\dotnet\sdk]

.NET Core runtimes installed:
  Microsoft.AspNetCore.All 2.1.19 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.1.19 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.0.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.1.19 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.0.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.0.3 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.2 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.5 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
affected-few area-blazor bug investigate severity-minor

Most helpful comment

Had a similar issue to this. I ended up putting up a hack, as we'd briefly have "Not Authorized" flash up before the authorized content showed (in some scenarios), so I just put in a base wait period for my unauthorized view, like so:

@page "/_unauthorized"
@layout EmptyLayout

@if (isWaiting)
{
    <Loader /> <span class="ml-2">Authorizing...</span>
}
else
{
    <h1 class="text-danger">Unauthorized.</h1>
    <h2 class="text-danger">I'm sorry, you're not authorized. If you believe this is an error, please contact a system administrator.</h2>
}

@code {
    // HACK: we are giving the auth system a little time to catch up and make sure we aren't authorized
    // We have certain scenarios where Unauthorized will flash during the auth process
    bool isWaiting = true;

    protected async override Task OnInitializedAsync()
    {
        await Task.Delay(2000);
        isWaiting = false;
    }
}

It doesn't solve the underlying problem but it does the trick for us, for now.

All 4 comments

Thanks for contacting us.
We're moving this issue to the Next sprint planning milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

Had a similar issue to this. I ended up putting up a hack, as we'd briefly have "Not Authorized" flash up before the authorized content showed (in some scenarios), so I just put in a base wait period for my unauthorized view, like so:

@page "/_unauthorized"
@layout EmptyLayout

@if (isWaiting)
{
    <Loader /> <span class="ml-2">Authorizing...</span>
}
else
{
    <h1 class="text-danger">Unauthorized.</h1>
    <h2 class="text-danger">I'm sorry, you're not authorized. If you believe this is an error, please contact a system administrator.</h2>
}

@code {
    // HACK: we are giving the auth system a little time to catch up and make sure we aren't authorized
    // We have certain scenarios where Unauthorized will flash during the auth process
    bool isWaiting = true;

    protected async override Task OnInitializedAsync()
    {
        await Task.Delay(2000);
        isWaiting = false;
    }
}

It doesn't solve the underlying problem but it does the trick for us, for now.

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

Same here, having this issue too. I want to call an async API in the AuthorizationHandler but <NotAuthorized> is processed before the API call returns a result. I hope this can be fixed.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

farhadibehnam picture farhadibehnam  路  3Comments

bgribaudo picture bgribaudo  路  3Comments

Kevenvz picture Kevenvz  路  3Comments

FourLeafClover picture FourLeafClover  路  3Comments

ermithun picture ermithun  路  3Comments