View-Based Authorization in ASP.NET Core

View-Based Authorization in ASP.NET Core

This blog is going to explain what is View-Based Authorization and how to implement it in ASP.NET Core. In some cases, the developer may need to show or hide the UI based on the user's identity.

For example, an admin can edit data, but should not allow guest users to edit data. In this case, the developer should show the edit link when the admin user logs in and hide the edit link when the guest user logs in. This process can be achieved through View-Based Authorization . Let's look at that step by step.

Step 1:
In the first step, I created a Users class to get user details. Also, I added two values to test View-Based Authorization . For real use, you need to get these user details from the database.

Users.cs
public class Users
{
    public string Username { get; set; }
    public string Password { get; set; }
    public string Role { get; set; }
    public DateTime DateOfBirth { get; set; }

    public IEnumerable<Users> GetUsers()
    {
        return new List<Users>() { new Users { Username = "peter", Password = "123", Role = "Admin", DateOfBirth= DateTime.Parse("02/02/1990") },
                                   new Users { Username = "parker", Password = "456", Role = "Guest", DateOfBirth= DateTime.Parse("04/06/2005") }};
    }
}

Step 2:
This step is a simple cookie authentication, which handles the authentication process. Username, role and date of birth are stored in the claim. Thus these values can be used to verify the user.

AccountController.cs
public class AccountController : Controller
{
    [HttpGet]
    public ActionResult Login()
    {
        Users user = new Users();
        return View(user);
    }

    [HttpPost]
    public async Task<ActionResult> Login(Users user)
    {
        var usrs = new Users();
        var result = usrs.GetUsers().FirstOrDefault(u => u.Username == user.Username && u.Password == user.Password);
        if (result != null) // Check DB value
        {
            var userClaims = new List<Claim>()
                        {
                        new Claim(ClaimTypes.Name, result.Username),
                        new Claim(ClaimTypes.Role, result.Role),
                        new Claim(ClaimTypes.DateOfBirth, result.DateOfBirth.ToString()),
                        };

            var identity = new ClaimsIdentity(userClaims, CookieAuthenticationDefaults.AuthenticationScheme);

            var userPrincipal = new ClaimsPrincipal(new[] { identity });

            await HttpContext.SignInAsync(userPrincipal);

            return RedirectToAction("Index", "Home");
        }

        return View(user);
    }

    public async Task<ActionResult> Logout()
    {
        await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
        return RedirectToAction("Login", new Users());
    }
}

Step 3:
This step is a Startup.cs class. Here I have created the policy-based authorization with the name ViewBasedAuthorizationDemo

Starup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
            .AddCookie(options =>
            {
                options.Cookie.Name = "SampleCookieAuth";
                options.LoginPath = "/Account/Login";
            });

    services.AddAuthorization(options =>
    {
        options.AddPolicy("ViewBasedAuthorizationDemo", policy =>
        {
            policy.RequireRole("Admin");
            policy.Requirements.Add(new AgeRequirement(18));
        });
    });

    services.AddSingleton<IAuthorizationHandler, AgeRequirementHandler>();

    services.AddControllersWithViews();
}
Added UseAuthorization() middleware in the configuration next to UseAuthentication()
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
  ...
  ...

    app.UseAuthentication();
    app.UseAuthorization();

  ...
  ...
}

Step 4:
The following is a handler code. It checks the age range. Whether the user is over 18 years of age or not.

public class AgeRequirement : IAuthorizationRequirement
{
    public int Age { get; }
    public AgeRequirement(int age)
    {
        Age = age;
    }
}

public class AgeRequirementHandler : AuthorizationHandler<AgeRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AgeRequirement requirement)
    {
        DateTime userDateOfBirth = DateTime.Parse(context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth).Value);

        // Get Age
        int age = DateTime.Today.Year - userDateOfBirth.Year;
        if (age >= requirement.Age)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

Step 5:
This is the main step in view authorization. Here IAuthorizationService is injected into the view. The AuthorizeAsync system checks the authentication policy to determine if the edit link should be visible to the user. If the policy succeeds, it will show the edit option, otherwise no.

Index.cshtml
@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService
@model List<MovieList>

<div align="right">
    <a asp-controller="Account" asp-action="Logout">Logout</a>
</div>
<br />
<br />

<table class="table">
    <tr>
        <th scope="col">Movie Name</th>
        <th scope="col">Released Date</th>
        <th scope="col">Co Production</th>
        <th scope="col">Action</th>
    </tr>
    @{
        foreach (var item in Model)
        {
            <tr>
                <td>
                    @item.MovieName
                </td>
                <td>
                    @item.ReleasesYear
                </td>
                <td>
                    @item.CoProduction
                </td>
                <td>
                  @if ((await AuthorizationService.AuthorizeAsync(User, "ViewBasedAuthorizationDemo")).Succeeded)
                    {
                        <a role="link" href="@Url.Action("Edit", "Home", new { id = item.Id })">Edit</a>
                    }
                </td>
            </tr>
        }
    }
</table>

Output
The following is an output of the above code. User Peter is an admin and his age is over 18, so the edit link was created for him. User Parker does not have an admin, so the edit link was not created for him.

View-Based Authorization in ASP.NET Core

I hope this helps you. Keep coding.

Comments

Popular posts from this blog

Entity Framework Core (EF) with SQL Server LocalDB

Creating a C# Azure Function with Visual Studio: Step-by-Step Guide

Exploring EventCallback in Blazor: Building Interactive Components