I'm using a custom policy to secure a page in a server-side Blazor app. All is working well except one of my policies requires knowing the query parameters of the request. For example, the URI path is something like https://mywebsite/profile/1234, which is used to view/edit the profile with id=1234. Obviously we only want the user with profileId = 1234 editing this page. How can I check for this in my IAuthorizationHandler
?
I tried injecting the HttpContext
and reading the request.Query items, but it's just always "/" or "/_blazor", because it's a SPA course. I tried injecting NavigationManager
(formerly UriHelper
) to get the URI from there, but got an error:
'RemoteNavigationManager' has not been initialized.
I also tried using the Resource parameter to pass the information into my handler. I couldn't find any examples of how to do this, so this is my attempt:
Here is my profile.razor code, where I am limiting access with Policy="CanEditProfile"
@inject NavigationManager NavigationManager
<AuthorizeView Policy="CanEditProfile">
<NotAuthorized>
<h2 class="mt-5">You are not authorized to view this page</h2>
</NotAuthorized>
<Authorized>
<div class="container my-profile">
<h2>My Profile</h2>
And my IAuthorizationHandler
code:
public Task HandleAsync(AuthorizationHandlerContext context)
{
if (context == null || httpContextAccessor.HttpContext == null) return Task.CompletedTask;
// try getting path from httpContext
var path = httpContextAccessor.HttpContext.Request.Path.Value;
Console.WriteLine($"Path = {path}"); // this is always "/_blazor"
// try getting path from resource, passed in from blazor page component
var resource = context.Resource?.ToString();
Console.WriteLine($"Resource = {resource}"); // this is always null
var pendingRequirements = context.PendingRequirements.ToList();
foreach (var requirement in pendingRequirements)
{
if (requirement is EditMemberPermission)
{
// if this user is admin, then grant permission
var isAdmin = context.User.IsInRole("Admin");
if (isAdmin)
{
context.Succeed(requirement);
continue;
}
// get requested memberId from uri parameter, e.g. /profile/1234
var requestedMemberId = // How do I get this?
if (IsOwner(context.User, requestedMemberId))
{
context.Succeed(requirement);
}
}
}
return Task.CompletedTask;
}
Any ideas on how to achieve this? It seems like it would be a common scenario, to secure a page based on which page data (query param "id") the user is trying to access. Many of the examples mention securing a Resource, and show it as an optional parameter, but no examples I could find show actually passing a value and using it. How can you secure a resource if you don't know what the resource is? I thought there might be a way to pass the Resource parameter from the .razor page to the Auth handler, like this, but I haven't gotten that to work either.
<AuthorizeView Policy="CanEditProfile" Resource="<pass url somehow?>" />
Thanks in advance.
I got this working by using this code in my profile.razor:
This gets the MemberId parameter from the route, and passes it as a Resource to my
IAuthorizationHandler
. In that handler method, I can fetch it like this: