Saturday, September 7, 2019

Authorization in views in asp.net core mvc

We will discuss how to perform authorization checks in views in asp.net core mvc. This technique is very useful, if you want to show or hide UI elements based on whether the logged-in user has access to them or not.

Role based authorization check in views in asp.net core mvc

Show Manage navigation menu item only if the user is signedin and member of the Admin role.


role based authorization check in views in asp.net core mvc

Navigation menu is in the layout view. To check if the user is signedin, inject ASP.NET Core SignInManager service

@using Microsoft.AspNetCore.Identity
@inject SignInManager<ApplicationUser> SignInManager
  • SignInManager service IsSignedIn(User) method returns true if the user is signed in otherwise false.
  • To check if the User is a member of the given role, use IsInRole() method 
@if (SignInManager.IsSignedIn(User) && User.IsInRole("Admin"))
{
    <li class="nav-item dropdown">
        <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink"
           data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
            Manage
        </a>
        <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
            <a class="dropdown-item"
               asp-controller="Administration" asp-action="ListUsers">
                Users
            </a>
            <a class="dropdown-item"
               asp-controller="Administration" asp-action="ListRoles">
                Roles
            </a>
        </div>
    </li>
}

Claims based authorization check in views in asp.net core mvc

On the ListRoles view, we want to display Edit button ONLY if the signed-in user has satisfied EditRolePolicy.

claims based authorization check in views in asp.net core mvc

To satisfy EditRolePolicy, the logged-in user must have Edit Role claim. We discussed claim policies and claims based authorization in detail in Part 94 of ASP.NET Core tutorial.

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthorization(options =>
    {
        options.AddPolicy("EditRolePolicy", policy => policy.RequireClaim("Edit Role"));
    });
}

To check if the signed-in user satisfies EditRolePolicy, inject IAuthorizationService service into the view

@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService authorizationService;

Pass the user and the name of the policy as parameters to AuthorizeAsync() method of IAuthorizationServiceSucceeded property returns true if the policy is satisfied, otherwise false.

@if ((await authorizationService.AuthorizeAsync(User, "EditRolePolicy")).Succeeded)
{
    <a asp-controller="Administration" asp-action="EditRole"
       asp-route-id="@role.Id" class="btn btn-primary">
        Edit
    </a>
}

Authorization checks in views alone is not enough

It's not enough if we just show or hide UI elements on the view. The respective controller actions must also be protected. Otherwise, the user can directly type the URL in the address bar and access the resources.

In our example, though Edit button is hidden, the user can directly type the following URL to get to the EditRole action

http://localhost:0001/Administration/EditRole/RoleIdGuidHere

Make sure to protect the respective controller action as well

[Authorize(Policy = "EditRolePolicy")]
public async Task<IActionResult> EditRole(string id)
{
    // Code
}

Service injection in multiple views

If you need IAuthorizationService in multiple views, consider importing in _ViewImports.cshtml, so you do not have to import it in every individual view.

No comments:

Post a Comment

How to register multiple implementations of the same interface in Asp.Net Core?

 Problem: I have services that are derived from the same interface. public interface IService { } public class ServiceA : IService { ...