Custom Authentication Filter in MVC

Custom Authentication Filter in ASP.NET MVC Application

In this article, I am going to discuss how to create a Custom Authentication Filter in MVC application. The Authentication Filter was introduced with MVC 5 and provides a great improvement for authenticating a user. As of now, there is no in-built Authentication Filer in MVC. So, if you want to use, then the one and the only way to create a custom authentication filter and use that filter in your application.

As of now, we have used two built-in filters i.e. Authorize and AllowAnonymous. The Authorize filter performs the authorization tasks for an authenticated user. A good example is a Role based authorization. The AllowAnonymous filter allows anonymous users to access certain Controllers/Actions. In this way, we can protect the entire application by using the Authorize and AllowAnonymous attribute.

What is the real reason behind Authentication filters?

Before Authentication Filter, as a developer, we use the Authorization filters for two purposes i.e. Authentication and Authorization. It was convenient because the Authorization filters were executed before executing any other action filters.  For example, before executing the actual action method, we can use an Authorization filter to redirect an unauthenticated user to a login page or some error page.

But now, you can separate the Authentication related tasks to a new custom authentication filter and performs the authorization related tasks using the authorization filters only. So, in simple words, we can say it is basically about separating of concerns which will provide the developers to focus on one aspect using one filter only.

How to create a Custom Authentication Filter in MVC?

In order to create a Custom Authentication filter in MVC, you need to create a class by implementing the IAuthenticationFilter Interface. This IAuthenticationFilter interface has 2 methods. Following is the class definition of IAuthenticationFilter interface.

creating a Custom Authentication Filter in MVC

OnAuthentication:

This method is used to authenticate the request. The AuthenticationContext provides us the necessary information which is required for performing authentication. We can use this information to make authentication decisions based on the current context. For example, we may decide to modify the ActionResult to different result type based on the authentication context, or we may decide to change the current principal based on the authentication context, etc.

OnAuthenticationChallenge:

This Method gets called when Authentication or Authorization is failed or after the execution of action method but before rendering the view. That means the OnAuthenticationChallenge method can run at various stages. 

For example, it can run after the AuthorizationFilters or it can run after Action Method execution completed and so on. Since this method runs at various stages, you now have the ability to change the action result based on the authentication.

Create a new Empty MVC Application

Open visual studio and select File => New => Project from the context menu as shown in the below image.

Create a new Empty MVC Application

After clicking on the “Project” link, a new dialog will pop up. In that, we are going to select “Web” templates from the left pane. From the middle pane, select “ASP.NET Web Application“. Provide a meaningful name to the project here I am giving my project name as “AuthenticationInMVC”. Finally, click on the “OK” button as shown in the below image

Creating new ASP.NET MVC Project

Once you click on the “OK” button a new dialog will pop up with the name “New ASP.NET Project” for selecting project Templates as shown in the below image.

Selecting Project Template

In this dialog, we are going to choose “Empty” and “MVC” project template with the Authentication type as “No Authentication” and then click on the “OK” button. Once you click on the OK button it will take some to time create the project for us.

Creating Login Model:

Create a class file with the name LoginModel within the Models folder and then copy and paste the following code in it.

using System.ComponentModel.DataAnnotations;
namespace AuthenticationInMVC.Models
{
    public class LoginModel
    {
        [Required(ErrorMessage = "Please Enter User Name")]
        [Display(Name = "User Name")]
        public string UserName { get; set; }

        [Required(ErrorMessage = "Please Enter Password")]
        [DataType(DataType.Password)]
        public string Password { get; set; }
    }
}

We created the above LoginModel class two properties i.e. Username and Password.

Creating Accounnt Controller:

Create a Controller with the name AccountController (Empty MVC5 Controller) within the Controllers Folder and then copy and paste the following code in it.

using System.Web.Mvc;
using AuthenticationInMVC.Models;
using System.Web.Security;

namespace AuthenticationInMVC.Controllers
{
    public class AccountController : Controller
    {
        [HttpGet]
        public ActionResult Login()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Login(LoginModel model)
        {
            if(ModelState.IsValid)
            {
                //Here we are checking the values with hardcoded admin and admin
                //You can check these values from a database
                if (model.UserName.ToLower() == "admin" && model.Password == "admin")
                {
                   //Store the Username in session
                   Session["UserName"] = model.UserName;

                    //Then redirect to the Index Action method of Home Controller
                    return RedirectToAction("Index", "Home");
                }
                else
                {
                    ModelState.AddModelError("", "Invalid User Name or Password");
                    return View(model);
                }
            }
            else
            {
                return View(model);
            }
        }
    }
}

As you can see, we created the Account Controller with two Action Methods, one of which handles the HttpGet Request while the other one handles the HttpPost Request.

In Post Request, first we are checking the ModelState is valid or not. If the model state is not valid then we are simply returning the model to the View which will display the model error and allows the user to submit the credentials again.

If it is valid then we are going to check the Username and Password is valid or not. Here to make things simple we are checking the credentials against the hardcoded values but in real-time, you need to check these credentials from a database or any persistent storage.

If the user name and password are not valid then we will stay in the same login page by providing the error message that Invalid User Name or Password. On the other hand, if the credentials are valid then we set Session[“UserName”] value from the UserName property of the Model object and then redirect the user to the Index View of Home Controller.

Creating Login View:

Create the Login View of Account Controller and then copy and paste the following code in it.

@model AuthenticationInMVC.Models.LoginModel

@{
    ViewBag.Title = "Login";
}
<h2>Login</h2>
@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.UserName, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.UserName, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.UserName, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Password, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Password, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Password, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
Creating a Custom Authentication Filter in MVC:

Create a class file with the name CustomAuthenticationFilter.cs within the Models folder and then copy and paste the following code in it. The class is inherited from ActionFilterAttribute and IAuthenticationFilter interface. We want to use this CustomAuthenticationFilter class as an attribute, so we inherit this class from ActionFilterAttribute class. Along the same line, we want this class an Authentication Filter so inherit from the IAuthenticationFilter interface.

using System;
using System.Web.Mvc;
using System.Web.Mvc.Filters;
using System.Web.Routing;

namespace AuthenticationInMVC.Models
{
    public class CustomAuthenticationFilter : ActionFilterAttribute, IAuthenticationFilter
    {
        public void OnAuthentication(AuthenticationContext filterContext)
        { 
            if (string.IsNullOrEmpty(Convert.ToString(filterContext.HttpContext.Session["UserName"])))
            {
                filterContext.Result = new HttpUnauthorizedResult();
            }
        }

        public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
        {
            if (filterContext.Result == null || filterContext.Result is HttpUnauthorizedResult)
            {
                //Redirecting the user to the Login View of Account Controller
                filterContext.Result = new RedirectToRouteResult(
               new RouteValueDictionary
               {
                    { "controller", "Account" },
                    { "action", "Login" }
               });

                //If you want to redirect to some error view, use below code
                //filterContext.Result = new ViewResult()
                //{
                //    ViewName = "Login"
                //};
            }
        }
    }
}

The OnAuthentication method is going to run before the OnAuthenticationChallenge method. Within the OnAuthentication method, we are just checking the Session[“UserName”] value is null or empty. If the Session[“UserName”] value is NULL or Empty then we are going to set the Result of the filterContext object to HttpUnauthorizedResult.

The OnAuthenticationChallenge method gets called when Authentication or Authorization is failed and also this method is called after the Execution of Action Method but before rendering the View. Here, within the OnAuthenticationChallenge method, we are just checking the Result value of the filterContext object. If the Result of the filterContext object is either null or HttpUnauthorizedResult then we just redirecting the request to the Login view of Account Controller.

Using Custom Authentication Filter in MVC:

In order to test the Custom Authentication Filter in MVC, Let’s add a Controller with the name Home within the Controllers folder. Once you create the Home Controller then copy and paste the following code in it.

using System.Web.Mvc;
using AuthenticationInMVC.Models;

namespace AuthenticationInMVC.Controllers
{ 
    public class HomeController : Controller
    {
        [CustomAuthenticationFilter]
        public ActionResult Index()
        {
            return View();
        }

        [CustomAuthenticationFilter]
        public ActionResult Contact()
        {
            return View();
        }
        
        public ActionResult About()
        {
            return View();
        }
    }
}

As you can see, we created the above Home Controller class with three action methods. Two action methods i.e. Index and Contact are decorated with the custom Authentication Filter attribute. Now let’s create the respective views.

Index.cshtml

@{
    ViewBag.Title = "Index";
}
<h2>Index View From Home Controller</h2>

Contact.cshtml

@{
   ViewBag.Title = "Contact";
}
<h2>Contact View From Home Controller</h2>
About.cshtml
@{
   ViewBag.Title = "About";
}
<h2>About View From Home Controller</h2>

That’s it. We are done with our implementation. Now run the application and you will see when you want to access the Index and Contact page, it will navigate to the Login page of Account Controller. But you can access the About page as we have not applied our custom authentication filter on this action method. Now login with the proper credentials and once you login then you can access each page of the application.

In this article, I try to explain how to create a Custom Authentication filter in MVC application step by step with a simple example. I hope you understood how to create and use custom authentication filter in ASP.NET MVC application. 

Leave a Reply

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