Authorization Filters in ASP.NET Core MVC

Authorization Filter in ASP.NET Core MVC

In this article, I will discuss the Authorization Filter in ASP.NET Core MVC Application with Examples. Please read our previous article discussing Response Caching in ASP.NET Core Applications. As part of this article, we will discuss the following pointers in detail.

  1. What is the Authorization Filter in ASP.NET Core MVC?
  2. What is Authentication?
  3. What is Authorization?
  4. Examples to Understand Authorization Filter in ASP.NET Core MVC
  5. Custom Authorization Filter in ASP.NET Core MVC
  6. When to Use Authorization Filter in ASP.NET Core MVC?
What is the Authorization Filter in ASP.NET Core MVC?

In ASP.NET Core MVC, the Authorization Filter allows us to apply authorization rules to controllers and actions within our application. Authorization filters determine whether a user can access a particular resource or perform a specific action based on authentication and authorization criteria.

Authorization filters in ASP.NET Core MVC are a part of the ASP.NET Core’s filter pipeline and are used to implement authorization on controller actions. These filters run before the action method is executed, ensuring the user has permission to access the method.

  • Purpose: Authorization filters are used to implement authentication and authorization logic before the target resource is executed. They are responsible for checking if a user is allowed to perform an action or access a resource.
  • How They Work: Authorization filters are executed after the routing but before model binding and other action filters. If the authorization fails (e.g., the user does not have the required permissions), the filter short-circuits the request, and the action method does not execute.
What is Authentication?

Authentication is a process that ensures and confirms a user’s identity. In other words, we can say that it is a process to validate someone against some data source. Let’s have a look at the following diagram.

What is Authentication?

Let us understand Authentication from a layman’s point of view. The above image shows the different sections of an IT Company like Reception, HR Section, Accounts Section, Server Room, etc. At the gate, we have biometrics to verify the employee. Suppose one user or one employee comes. This biometrics checks the employee credentials against some data source, and if it is found that the employee is valid, it only allows entering into the campus. This is nothing but Authentication.

What is Authorization?

Authorization is a security mechanism determining whether users can access a particular resource. The most important point you must remember is that authentication happens first and then only authorization. Let us have a look at the following image.

What is Authorization?

As shown in the above image, once the user is authenticated, he enters the Campus. Then, Authorization comes into the picture. Within the campus, which section he may be allowed to enter is determined by the Authorization process. The Role of the user does this. If the user has list privileges, he may not allow each section. On the other hand, if the user has the highest privileges, he may be allowed to enter each section.

Types of Authorization Filters in ASP.NET Core MVC:

By default, in the ASP.NET Core MVC applications, all the action methods of all controllers can be accessed by both authenticated and anonymous users. But if you want the action methods to be available only for authenticated and authorized users, you need to use the Authorization Filter in ASP.NET Core MVC.

Built-in Authorization Filters in ASP.NET Core:

ASP.NET Core provides two built-in attributes, [Authorize] and [AllowAnonymous], that can be used as filters.

  • Authorize Attribute: The [Authorize] attribute in ASP.NET Core MVC specifies that only authenticated users or users with certain roles or policies can access a particular action method or controller. The [Authorize] attribute specifies that the associated action method or controller requires the user to be authenticated. 
  • AllowAnonymous Attribute: The [AllowAnonymous] attribute in ASP.NET Core MVC specifies that a particular action method or controller should allow anonymous access, even when an [Authorize] attribute is applied at the controller or action level. In other words, it permits unauthenticated users to access the decorated resource, bypassing any authentication and authorization checks that might be in place at higher levels.
Custom Authorization Filter in ASP.NET Core:

You can also create Custom Authentication filters. To create Custom Authentication in ASP.NET Core MVC, you need to create a class implementing the IAuthorizationFilter or IAsyncAuthorizationFilter interface and provide implementations for the OnAuthorization method, where you need to write the custom authentication logic as per your business requirements. Then, register the filter globally or apply it to controllers or action methods using attributes.

Examples to Understand Authorization Filter in ASP.NET Core MVC:

Let us understand the Authorize and AllowAnonymous Filters with an example. First, create a new ASP.NET Core Application using the Model-View-Controller Project Template. Once you create the Project, then modify the Home Controller as follows:

using Microsoft.AspNetCore.Mvc;
namespace FiltersDemo.Controllers
{
    public class HomeController : Controller
    {
        public string NonSecureMethod()
        {
            return "This method can be accessed by everyone as it is non-secure method";
        }

        public string SecureMethod()
        {
            return "This method needs to be access by authorized users as it SecureMethod";
        }

        public string Login()
        {
            return "This is the Login Page";
        }
    }
}

As you can see, we created the above HomeController with three action methods, i.e., NonSecureMethod, SecureMethod, and Login. We want the SecureMethod to be accessed by authenticated users while the NonSecureMethod and Login methods to be accessed by anyone. Whenever an unauthenticated user wants to access the SecureMethod, we must redirect that user to the Login action method.

At this point, authenticated and anonymous users can access the SecureMethod and the NonSecureMethod methods using the following two URLs.

/Home/SecureMethod

/Home/NonSecureMethod

If you want the Secure Method to be accessed only by authenticated and authorized users, then you need to decorate this method with the Authorize attribute, as shown below.

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace FiltersDemo.Controllers
{
    public class HomeController : Controller
    {
        public string NonSecureMethod()
        {
            return "This method can be accessed by everyone as it is non-secure method";
        }

        [Authorize] //Requires authentication for the SecureMethod 
        public string SecureMethod()
        {
            return "This method needs to be access by authorized users as it SecureMethod";
        }

        public string Login()
        {
            return "This is the Login Page";
        }
    }
}

Now run the application and navigate to /Home/SecureMethod, and you will see the following Internal Server Error.

Examples to Understand Authorization Filter in ASP.NET Core MVC

Instead of displaying the above error page, we need to redirect the user to the Login Page. In the later part of this article, I will show you how to create Custom Authentication Filters to achieve the same in ASP.NET Core MVC Applications.

Can we Apply the Authorize Attribute at the Controller Level?

Applying the Authorize attribute at the controller level applies to all the action methods present within that controller. For a better understanding, please modify the Home Controller as follows. The Home Controller’s action methods are now protected with the Authorize Attribute. So, now only the authenticated users can access the SecureMethod(), NonSecureMethod(), and Login action methods.

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace FiltersDemo.Controllers
{
    [Authorize] //Requires authentication for the entire controller 
    public class HomeController : Controller
    {
        public string NonSecureMethod()
        {
            return "This method can be accessed by everyone as it is non-secure method";
        }

        public string SecureMethod()
        {
            return "This method needs to be access by authorized users as it SecureMethod";
        }

        public string Login()
        {
            return "This is the Login Page";
        }
    }
}

Now, suppose you want to allow anonymous access to the NonSecureMethod and Login method of the Home Controller. In that case, you need to decorate the NonSecureMethod and Login method with the AllowAnonymous attribute, as shown below. The AllowAnonymous attribute in ASP.NET Core MVC is used to skip the authorization enforced by the Authorization Filter.

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace FiltersDemo.Controllers
{
    [Authorize] //Requires authentication for the entire controller 
    public class HomeController : Controller
    {
        public string SecureMethod()
        {
            return "This method needs to be access by authorized users as it SecureMethod";
        }

        [AllowAnonymous]
        public string NonSecureMethod()
        {
            return "This method can be accessed by everyone as it is non-secure method";
        }

        [AllowAnonymous]
        public string Login()
        {
            return "This is the Login Page";
        }
    }
}

Note: If both Authorize and AllowAnonymous Attributes are applied to an action method, then the AllowAnonymous attribute will take priority and be accessed by any user.

Custom Authorization Filter in ASP.NET Core MVC:

Creating a Custom Authorization Filter in ASP.NET Core MVC allows us to implement custom logic to control access to our controllers or actions. In ASP.NET Core MVC, we can create custom Authorization Filters by implementing the IAuthorizationFilter interface and providing implementation to the OnAuthorization method, where we need to write the custom logic as per our requirements.

In ASP.NET Core MVC, we can create a custom authorization filter to redirect to the login page when a user is not authenticated. Let us see how we can create a custom authorization filter to achieve this:

Create a class file named CustomAuthorizationFilterAttribute.cs, and then copy and paste the following code. As you can see, the following class is inherited from the Attribute and IAuthorizationFilter classes, so we can use this class as an Attribute. This class also implements the IAuthorizationFilter interface and provides the implementation for the OnAuthorization method, where we have written our custom authorization logic.

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Security.Claims;

namespace FiltersDemo.Models
{
    public class CustomAuthorizationFilterAttribute : Attribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            // Your custom authorization logic here
            if (!IsAuthorized(context.HttpContext.User))
            {
                // If not authenticated, redirect to the login page
                context.Result = new RedirectToRouteResult(new RouteValueDictionary
                {
                    { "controller", "Home" },   // Change "Home" to your login controller name
                    { "action", "Login" }       // Change "Login" to your login action method name
                });
            }
        }

        private bool IsAuthorized(ClaimsPrincipal user)
        {
            // Check if the user is authenticated
            // Implement your custom authorization logic here
            // Check roles, claims, policies, or any other criteria
            // Return true if authorized, false if not

            return false; // For demonstration purposes
        }
    }
}

Now, we need to decorate the controller or action method where we need to implement our custom authorization logic. Let us decorate the SecureMethod with our Custom Authorization Filter Attribute. So, modify the Home Controller as follows:

using FiltersDemo.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace FiltersDemo.Controllers
{
    public class HomeController : Controller
    {
        [CustomAuthorizationFilterAttribute] // Apply the custom CustomAuthorizationFilterAttribute 
        public string SecureMethod()
        {
            return "This method needs to be access by authorized users as it SecureMethod";
        }

        [AllowAnonymous]
        public string NonSecureMethod()
        {
            return "This method can be accessed by everyone as it is non-secure method";
        }

        [AllowAnonymous]
        public string Login()
        {
            return "This is the Login Page";
        }
    }
}

With the above changes in place, visit the SecureMethod, and you will see that it will redirect to the Login Page.

Creating a Custom Authorization Filter

In the previous example, the CustomAuthorizationFilterAttribute class is inherited from the Attribute class, and that’s why we apply the CustomAuthorizationFilterAttribute directly to the action methods and controller. Let us remove the inherited Attribute class from the CustomAuthorizationFilterAttribute class definition, and let’s inherit from the IAuthorizationFilter interface. So, modify the CustomAuthorizationFilterAttribute class as follows:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Security.Claims;

namespace FiltersDemo.Models
{
    public class CustomAuthorizationFilter : IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            // Your custom authorization logic here
            if (!IsAuthorized(context.HttpContext.User))
            {
                // If not authenticated, redirect to the login page
                context.Result = new RedirectToRouteResult(new RouteValueDictionary
                {
                    { "controller", "Home" },   // Change "Account" to your login controller name
                    { "action", "Login" }       // Change "Login" to your login action method name
                });
            }
        }

        private bool IsAuthorized(ClaimsPrincipal user)
        {
            // Check if the user is authenticated
            // Implement your custom authorization logic here
            // Check roles, claims, policies, or any other criteria
            // Return true if authorized, false if not

            return false; // For demonstration purposes
        }
    }
}
Register the Filter Globally, on a Controller, or an Action:

You can register your filter globally, which means it will be applied to all controllers and actions in your application. In your Program.cs, you can add the filter as follows.

builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add(new CustomAuthorizationFilter());
});
Using Authentication Filter at Controller and Action Method Level:

You can apply the Custom Authentication Filter to a specific controller or action method using the built-in ServiceFilter and TypeFilter Attribute. We use the ServiceFilter attribute in the code below to specify the CustomAuthorizationFilter.

using FiltersDemo.Models;
using Microsoft.AspNetCore.Mvc;

namespace FiltersDemo.Controllers
{
    public class HomeController : Controller
    {
        [ServiceFilter(typeof(CustomAuthorizationFilter))]
        public string Index()
        {
            return "String Data from Index Action Method";
        }
    }
}
IAsyncAuthorizationFilter Example in ASP.NET Core MVC

Below is an example of an IAsyncAuthorizationFilter in ASP.NET Core MVC. This type of filter is suitable for performing asynchronous operations, such as database calls or any I/O-bound work, within your authorization logic.

Create the Custom Authorization Filter:

First, implement the IAsyncAuthorizationFilter interface to create your asynchronous authorization filter:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace FiltersDemo.Models
{
    public class CustomAsyncAuthorizationFilter : IAsyncAuthorizationFilter
    {
        public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            // Your asynchronous custom authorization logic here
            bool isAuthorized = await CheckUserAuthorizationAsync(context);

            if (!isAuthorized)
            {
                // If not authenticated, redirect to the login page
                context.Result = new RedirectToRouteResult(new RouteValueDictionary
                {
                    { "controller", "Home" },   // Change "Account" to your login controller name
                    { "action", "Login" }       // Change "Login" to your login action method name
                });
            }
        }

        private async Task<bool> CheckUserAuthorizationAsync(AuthorizationFilterContext context)
        {
            // Implement your asynchronous authorization logic here
            // For example, you can check user permissions, roles, etc., using async calls
            await Task.Delay(1000); // Simulate async work, like a database call

            // Return true if authorized, false otherwise
            return false;
        }
    }
}

In the CheckUserAuthorizationAsync method, replace the simulated async work with actual logic for determining authorization.

Register the Filter:

You can register the filter globally or on specific controllers or actions:

Globally:

In your Program.cs:

builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add(new CustomAsyncAuthorizationFilter());
});
On a Controller or Action:

As an attribute:

using FiltersDemo.Models;
using Microsoft.AspNetCore.Mvc;

namespace FiltersDemo.Controllers
{
    [TypeFilter(typeof(CustomAsyncAuthorizationFilter))]
    public class SomeController : Controller
    {
        // All actions in this controller will use the CustomAsyncAuthorizationFilter
    }

    public class AnotherController : Controller
    {
        [TypeFilter(typeof(CustomAsyncAuthorizationFilter))]
        public async Task<IActionResult> SomeAction()
        {
            // This action will use the CustomAsyncAuthorizationFilter
            return View();
        }
    }
}

Note: Using asynchronous filters is advantageous when you have I/O-bound work as part of authorization. If your authorization logic is CPU-bound and doesn’t involve awaiting tasks, you need to stick with synchronous IAuthorizationFilter for simplicity.

Note: Once we discuss the ASP.NET Core Identity, you will see the real implementation with proper roles, claims, etc.

When to Use Authorization Filter in ASP.NET Core MVC?

Authorization filters in ASP.NET Core MVC should be used when you need to control access to specific controllers or actions within your web application based on authentication and authorization rules. Here are some common scenarios in which you should use authorization filters:

  • Securing Sensitive Data or Functionality: Use authorization filters to protect endpoints that access sensitive data or perform sensitive operations, ensuring that only authorized users can access them.
  • Role-Based Access Control: When you have different user roles in your application (like admin, user, moderator), and you want to restrict access to certain actions or controllers based on these roles.
  • Policy-Based Authorization: Policy-based authorization filters are ideal for more complex authorization logic beyond simple role checks, such as evaluating user claims or custom requirements.
  • Global Authorization Rules: If your application has a general rule that requires user authentication for most parts of the application, applying a global authorization filter is efficient and ensures a security baseline.
  • Custom Authorization Logic: In cases where the built-in [Authorize] attribute does not suffice for your specific authorization needs, you can implement custom authorization filters for more complex scenarios.
  • Error Handling: Authorization filters can also handle unauthorized access by redirecting users to login pages, displaying access-denied messages, or taking other appropriate actions.

In the next article, I will discuss Action Filters in ASP.NET Core MVC Application. Here, in this article, I try to explain the Authorization Filter in ASP.NET Core MVC Application with Examples. I hope you understand the need for and use of Authorization Filters in the ASP.NET Core MVC application.

Leave a Reply

Your email address will not be published. Required fields are marked *