1

I am writing an MVC app using .net core 3.1.

I have setup user policies in Startup.cs. There is an overall Admin Role, and a User and Admin Role for each Area. The Roles exist in the AspNetRoles table, and have been linked to users in AspNetUserRoles

services.AddAuthorization(options =>
{
    options.AddPolicy("RequireAuthenticatedUserPolicy", policy => policy.RequireAuthenticatedUser());
    options.AddPolicy("RequireAdmin", policy => policy.RequireRole("Admin"));
    options.AddPolicy("RequireUserAnchor", policy => policy.RequireRole("Admin,AnchorUser,AnchorAdmin"));
    options.AddPolicy("RequireUserDashboard", policy => policy.RequireRole("Admin,DashboardUser,DashboardAdmin"));
    options.AddPolicy("RequireUserReportGroups", policy => policy.RequireRole("Admin,ReportGroupsUser,ReportGroupsAdmin"));
    options.AddPolicy("RequireUserMaintenance", policy => policy.RequireRole("Admin,MaintenanceUser,MaintenanceAdmin"));
    options.AddPolicy("RequireUserMaps", policy => policy.RequireRole("Admin,MapsUser,MapsAdmin"));
    options.AddPolicy("RequireAdminAnchor", policy => policy.RequireRole("Admin,AnchorAdmin"));
    options.AddPolicy("RequireAdminDashboard", policy => policy.RequireRole("Admin,DashboardAdmin"));
    options.AddPolicy("RequireAdminReportGroups", policy => policy.RequireRole("Admin,ReportGroupsAdmin"));
    options.AddPolicy("RequireAdminMaintenancen", policy => policy.RequireRole("Admin,MaintenanceAdmin"));
    options.AddPolicy("RequireAdminMaps", policy => policy.RequireRole("Admin,MapsAdmin"));
});

The areas have attributes on their controller definitions. eg: the GroupsController

[Area("ReportGroups")]
[Authorize(Policy = "RequireUserReportGroups")]
public class GroupsController : Controller
{

The users roles are used to modify the sites menu, showing only sections they have access to in _Layout.cshtml

@if (User.IsInRole("Admin"))
{
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="Admin" asp-controller="Admin" asp-action="Index"><i class="fas fa-2x fa-chess-king" title="Admin"></i></a>
    </li>
}
@if (User.Identity.IsAuthenticated)
{
    <li class="nav-item">
        <span style="font-weight:bold; font-size:16px;">ORG<br />@User.Identity.GetOrgCode()</span>
    </li>
}
@if (User.IsInRole("AnchorUser") || User.IsInRole("Admin"))
{
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="Anchor" asp-controller="Home" asp-action="Index">
            <i class="fas fa-2x fa-anchor" title="Anchor"></i>
        </a>
    </li>
}

@if (User.IsInRole("DashboardUser") || User.IsInRole("DashboardAdmin") || User.IsInRole("Admin"))
{
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="Dashboard" asp-controller="DriverBehaviour" asp-action="Index">
            <i class="fas fa-2x fa-chart-area" title="Dashboard"></i>
        </a>
    </li>
}

The links on the home page are rendering correctly. eg: https://localhost:44322/Maintenance/Home

When they are clicked, they redirect to eg: https://localhost:44322/Account/AccessDenied?ReturnUrl=%2FMaintenance which is in addition to not working as expected, a 404 error.

Querying the Role membership and having it return true would indicate I have permission. Have I missed some config somewhere? And I querying the Roles incorrectly?

There is one gotcha. The AdminController returns fine. Its a basic scaffolded controller which just has a View saying "This is the Admin Controller"


Edit 2020-07-01

The solution was to change the entries in RequireRole. It is a list of strings, not a comma separated string. This is also why the only page using RequireAdmin worked.

services.AddAuthorization(options =>
{
    options.AddPolicy("RequireAuthenticatedUserPolicy", policy => policy.RequireAuthenticatedUser());
    options.AddPolicy("RequireAdmin", policy => policy.RequireRole("Admin"));
    options.AddPolicy("RequireUserAnchor", policy => policy.RequireRole("Admin","AnchorUser","AnchorAdmin"));
    options.AddPolicy("RequireUserDashboard", policy => policy.RequireRole("Admin","DashboardUser","DashboardAdmin"));
    options.AddPolicy("RequireUserReportGroups", policy => policy.RequireRole("Admin","ReportGroupsUser","ReportGroupsAdmin"));
    options.AddPolicy("RequireUserMaintenance", policy => policy.RequireRole("Admin","MaintenanceUser","MaintenanceAdmin"));
    options.AddPolicy("RequireUserMaps", policy => policy.RequireRole("Admin","MapsUser","MapsAdmin"));
    options.AddPolicy("RequireAdminAnchor", policy => policy.RequireRole("Admin","AnchorAdmin"));
    options.AddPolicy("RequireAdminDashboard", policy => policy.RequireRole("Admin","DashboardAdmin"));
    options.AddPolicy("RequireAdminReportGroups", policy => policy.RequireRole("Admin","ReportGroupsAdmin"));
    options.AddPolicy("RequireAdminMaintenancen", policy => policy.RequireRole("Admin","MaintenanceAdmin"));
    options.AddPolicy("RequireAdminMaps", policy => policy.RequireRole("Admin","MapsAdmin"));
});
6
  • Hi, could you show the AuthorizationHandler code? Commented Jun 30, 2020 at 9:49
  • I... do not appear to have one. Reading this page after googling AuthorizationHandler. (Thanks @MichelleWang) Have added IAuthorizationService and IAuthorizationHandler, but not sure where to put AuthorizeAsync as its a Task, not a class Commented Jun 30, 2020 at 23:59
  • RequireRole() takes a string array or list, not a comma delimited value. Could that be your issue? Commented Jul 1, 2020 at 1:16
  • @bugnuker possibly. Pretty sure that is based on example from MS’s site. Commented Jul 1, 2020 at 1:26
  • @bugnuker I think I confused between the specifying the Authorization attribute, which is a csv, and the specifying the role, which isn’t. Will update when back at desk and test Commented Jul 1, 2020 at 1:30

1 Answer 1

1

In your example, you are using a comma delimited value for the role names (see below)

options.AddPolicy("RequireUserAnchor", policy => policy.RequireRole("Admin,AnchorUser,AnchorAdmin"));

The method "RequireRole" takes a string array or a List.

You could try to change your code to:

options.AddPolicy("RequireUserAnchor", policy => policy.RequireRole(new string[] {"Admin","AnchorUser","AnchorAdmin"}));

Hopefully this helps!

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.