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?
.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]
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.
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:
It doesn't solve the underlying problem but it does the trick for us, for now.