Home > Software design >  How would I dynamically set the allowed Role or Policy for an Authorize View tag or attribute in Bla
How would I dynamically set the allowed Role or Policy for an Authorize View tag or attribute in Bla

Time:09-17

I am attempting to make a shared layout for a few applications. These applications are Blazor server-side apps. This layout has a small menu that can be configured via the appsettings file. One of the requirements is that we are able to show or hide certain menu items based on a list of Active Directory Groups in the appsettings. Below is an example of the JSON settings.

{
  "MenuItemName":"Protected Menu Item",
  "AllowedGroups": ["Administrator", "SpecialGroup", "SpecialGroup2"]
}

I believe we need to use either an <AuthorizeView> tag and/or an [Authorized] attribute on the page to ensure uses can't navigate to the page.

How would I actually dynamically fill in those tags? For example, take the following examples from the Microsoft Docs (https://docs.microsoft.com/en-us/aspnet/core/blazor/security/?view=aspnetcore-5.0#authorize-attribute-1). How would I replace the Roles="admin, superuser" with settings from within my Appsettings.json?

<AuthorizeView Roles="admin, superuser">
    <p>You can only see this if you're an admin or superuser.</p>
</AuthorizeView>

In another example using the [Authorized] attribute how would I dynamically populdate the Roles = "admin, superuser" section from the appsetings?

@page "/"
@attribute [Authorize(Roles = "admin, superuser")]

<p>You can only see this if you're in the 'admin' or 'superuser' role.</p>

CodePudding user response:

Attributes are embedded in the assembly at build time. Once the project/DLL is built, you cannot change the value again.

You need to perform runtime authorization. Since you're trying to check roles, inject the configuration and check if the user has any of the roles:

@inject IConfiguration Configuration
var isAllowed = Configuration.GetSection("AllowedGroups")
    .Get<string[]>()
    .Any(group => user.IsInRole(group));

Further info

CodePudding user response:

You could setup a policy to do it : This just reads a string array from "AllowedGroups" in appsettings.json but it demonstrates the fundamentals.

public class HasRolesFromConfigRequirement : IAuthorizationRequirement
{
    internal string[] allowedGroups;
    public HasRolesFromConfigRequirement(string[]? allowedGroups) => this.allowedGroups = allowedGroups;
}
public class HasRolesFromConfigHandler : AuthorizationHandler<HasRolesFromConfigRequirement>
{
    protected override Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
        HasRolesFromConfigRequirement requirement)
    {
        var rolesRequired = requirement.allowedGroups;
        if (rolesRequired is null)
        {
            context.Fail();
        }
        else
        {
            var hasRequiredRole = rolesRequired.Where(role => context.User.IsInRole(role)).Any();
            if(hasRequiredRole)
            {
                context.Succeed(requirement);
            }
            else
            {
                context.Fail();
            }
        }
        return Task.CompletedTask;
    }
}
public static class AuthorizationOptionsPolicyExtensions
{
    public static void AddPolicies(this IServiceCollection services, IConfiguration configuration)
    {
        services.AddScoped<IAuthorizationHandler, HasRolesFromConfigHandler>();
        services.AddAuthorizationCore(options => options.ConfigurePolicies(configuration));
    }

    public static AuthorizationOptions ConfigurePolicies(this AuthorizationOptions options, IConfiguration configuration)
    {
        var localConfiguration = configuration.Get<LocalConfiguration>();
        options.AddPolicy("HasARequiredRole", policy => policy.Requirements.Add(new HasRolesFromConfigRequirement(localConfiguration.AllowedGroups)));
        return options;
    }

}
<AuthorizeView Policy="HasARequiredRole">
    <div>
        Has A Required Role
    </div>
</AuthorizeView>
@page "/fetchdata"
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using DynamicRolesPolicy.Shared
@attribute [Authorize(Policy = "HasARequiredRole")]
@inject HttpClient Http

<PageTitle>Weather forecast</PageTitle>
...

A .net6(rc1) repo.

  • Related