Custom authentication filter in ASP.NET MVC

Sheonarayan
Posted by in ASP.NET MVC category on for Advance level | Points: 250 | Views : 31798 red flag
Rating: 4.67 out of 5  
 6 vote(s)

In this article, we shall learn how to create custom authentication filter in ASP.NET MVC 5+ using built in Authentication filter.
Recommendation
Read Working with Roles in ASP.NET Identity for MVC before this article.

Introduction

AuthenticationFilter has been introduced newly in ASP.NET MVC 5+ to provide fine-grain control over how users are authenticated for controllers and action methods. 

In this example, we shall learn how to create a custom authentication in ASP.NET MVC 5+.

Creating a custom Authentication Filter


Problem Scenario


Assume a scenario, where we want our Controller or an action methods available only to user having role as Admin or SuperAdmin.

Normally, we would write following attribute to the controller

    [Authorize(Roles = "Admin, SuperAdmin")]
    public class AdminSuperAdminController : Controller
    {   

    }
In general, there is no problem in hard coding the Authorize attribute for role as Admin and SuperAdmin, however think about the scenario, where we have to filter many controllers or action methods in the project. In general, what would we do is to copy-paste the attribute everywhere.

This raises a concern of duplication and maintenance. Tomorrow, if we need to change role names to something else or need to add another role into it then we will have to find and replace from entire project. There are chances or errors in this plus a lot of work too.

There can be many other scenarios where custom authentication filter is required and in all those scenario, this approach can be followed.

Solution


The solution of this problem is to create a custom authentication filter and use that in the controller or action methods. If we need any change, we just need to modify the custom authentication filter code at one place and that will affect all controller and action methods that is using this custom filter.

How to create a custom Authentication Filter?

To create a custom authentication filter, add a folder into the project called "CustomAttributes" (the folder name can be anything but better to keep it meaningful) and add a file called AdminSuperAdminAttribute.cs.



Now add following lines of code into AdminSuperAdminAttribute.cs file.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Filters;

namespace MVCInBuiltFeatures.CustomAttributes
{
    public class AdminSuperAdminAttribute : FilterAttribute, IAuthenticationFilter
    {
        string superAdminRole = "SuperAdmin"; // can be taken from resource file or config file
        string adminRole = "Admin"; // can be taken from resource file or config file

        public void OnAuthentication(AuthenticationContext context)
        {
            if (context.HttpContext.User.Identity.IsAuthenticated && 
               (context.HttpContext.User.IsInRole(superAdminRole) 
                || context.HttpContext.User.IsInRole(adminRole)))
            {
                // do nothing
            }
            else
            {
                context.Result = new HttpUnauthorizedResult(); // mark unauthorized
            }
        }

        public void OnAuthenticationChallenge(AuthenticationChallengeContext context)
        {
            if (context.Result == null || context.Result is HttpUnauthorizedResult)
            {
                context.Result = new RedirectToRouteResult("Default",
                    new System.Web.Routing.RouteValueDictionary{
                        {"controller", "Account"},
                        {"action", "Login"},
                        {"returnUrl", context.HttpContext.Request.RawUrl}
                    });
            }
        }
    }
}
In the above code snippet, we are doing following:

First, we have inherited this class file with FilterAttribute and IAuthenitcaitonFilter interface. For this, we need to add couple of namespaces as shown in the above code snippet.

Next, we have taken two variables and hard coded the role names. In real time scenario, we might not hard code  role name but can get from resource file, web.config file or from the database so that if role name changes, we do not need to change the code, rebuild and deploy the project. We can just change the source (Resource file, web.config or database) and we are done.

Interface IAuthenitcaitonFilter force us to implement a method named OnAuthentication and OnAuthenticationChallenge event only executes when OnAuthentication method has set the result.

In above code snippet, OnAuthenticationChallenge method will only executes when a request goes into the else block on OnAuthentication method and it redirects the user to Login page with returnUrl as querystring.

In OnAuthentication method, we have checked following
  • if user is authenticated and 
  • if user role is SuperAdmin or 
  • if user role is Admin
then do nothing else set the context.Result to HttpUnathorizedResult (unauthorized). The same is is being checked inside OnAuthenticationChallenge method and if it is null or HttpUnauthorizedResult then user is being redirected to the Login page of the website with current url as returnUrl querystring.

Once our Custom authentication filter is ready, we need to hook it up into the controller or action method as per our requirement; so lets do it.

To hook it up the controller, do something like below

    [AdminSuperAdmin]
    //[Authorize(Roles = "Admin, SuperAdmin")]
    public class AdminSuperAdminController : Controller
    { 

    }
and for controller action method, do something like below

        //
        // GET: /AdminSuperAdmin/Create
        [AdminSuperAdmin]
        public ActionResult Create()
        {
            return View();
        }
Remember that when we apply the attribute, we skip the "attribute" word suffix to the custom attribute class name.


What happens now?


  • In case of AdminSuperAdmin custom authentication filter is applied to the controller class, as soon as user try to go to this controller (eg. http://localhost:43415/AdminSuperAdmin/), he/she is redirected to the login  page with the current page url if he/she 
    • is not logged in
    • if logged in, is not SuperAdmin or
    • if logged in, is not Admin
  • In case of AdminSuperAdmin custom authentication filter is applied to the action method of the controller, user is redirect to the Login page with current page url, if
    • is not logged in
    • if logged in, is not SuperAdmin or
    • if logged in, is not Admin

Conclusion

Custom authentication filter is very handy when we need to control user authentication for controller and action methods in custom ways in ASP.NET MVC.

Hope this article was useful. Thanks for reading the article, if you found is useful please share to the social websites.

Keep visiting DotNetFunda.com for new articles, interview questions and other useful posts of your day to day developer life.

Page copy protected against web site content infringement by Copyscape

About the Author

Sheonarayan
Full Name: Sheo Narayan
Member Level: HonoraryPlatinum
Member Status: Administrator
Member Since: 7/8/2008 6:32:14 PM
Country: India
Regards, Sheo Narayan http://www.dotnetfunda.com
http://www.snarayan.com
Ex-Microsoft MVP, Author, Writer, Mentor & architecting applications since year 2001. Connect me on http://www.facebook.com/sheo.narayan | https://twitter.com/sheonarayan | http://www.linkedin.com/in/sheonarayan

Login to vote for this post.

Comments or Responses

Posted by: Poster on: 7/23/2014 | Points: 25
Great article, thanks.

Posted by: Raja on: 7/23/2014 | Points: 25
Yes, the example shown is very useful and it saves a lot many lines of duplicate codes.

Thanks for sharing.
Posted by: Jayakumars on: 7/30/2014 | Points: 25
hi
Sheo
can u provide Zip format Source this
Posted by: Sheonarayan on: 7/30/2014 | Points: 25
Hi Rajkumar,

There is nothing specific extra code that needs a separate .zip file. All the codes are self explanatory, if you have any specific question, let me know.

Thanks
Posted by: Ermahesh2009 on: 12/17/2015 | Points: 25
I am amazed the way you write this article , I earlier read on this topic but first time I got it .
All the codes are self explanatory with its purpose .

Login to post response

Comment using Facebook(Author doesn't get notification)