ASP.NET MVC Filter Based Authorization

We may use action filters for authorization in an ASP.NET MVC application. An action filter is an attribute that we can apply to a controller action or an entire controller.

The ASP.NET MVC framework includes several action filters including OutputCache, HandleError, and Authorize. Authorize action filter enables us to restrict access to a particular user or role.

Authorization filters implements the IAuthorizationFilter attribute. Authorization filters are used to implement authentication and authorization for controller actions. The ASP.NET MVC framework includes a base ActionFilterAttribute class. This class implements both the IActionFilter and IResultFilter interfaces and inherits from the Filter class.

The base ActionFilterAttribute class has the following methods that to override:
  • OnActionExecuting – called before a controller action is executed.
  • OnActionExecuted – called after a controller action is executed.
  • OnResultExecuting – called before a controller action result is executed.
  • OnResultExecuted – called after a controller action result is executed.
To achieve a filter-based authorization, first create AuthorizeAppAttribute class that inherits AuthorizeAttribute.

File: Utils/AuthorizeAppAttribute.cs

using System.Web.Mvc;
using System.Linq;
namespace Utils
{
    public class AuthorizeAppAttribute: AuthorizeAttribute
    {
        // set the View in case of unauthorized access
        public AuthorizeAppAttribute()
        {
            View = "UnAuthorized";
        }

        // view name
        public string View { get; set; }

        /// <summary>
        /// Check for Authorization
        /// </summary>
        /// <param name="filterContext"></param>
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            isUserAuthorized(filterContext);
        }

        /// <summary>
        /// Method to check if the user is Authorized or not
        /// if yes continue to perform the action else redirect to error page
        /// </summary>
        /// <param name="filterContext"></param>
        private void isUserAuthorized(AuthorizationContext filterContext)
        {
            if (filterContext.HttpContext.User.Identity.IsAuthenticated)
            {
                if (checkAuthorization(filterContext))
                    return;

                var vr = new ViewResult();
                vr.ViewName = View;

                ViewDataDictionary dict = new ViewDataDictionary();
                dict.Add("Message", "You are not authorized to use this page...");

                vr.ViewData = dict;

                var result = vr;

                filterContext.Result = result;
            }
        }

        /// <summary>
        /// Check for authorization
        /// Group membership for the user should match with the ControllerName and Role
        /// we may check for authorization from Active Directory, LDAP or Database
        /// </summary>
        /// <param name="filterContext"></param>
        /// <returns>is user authorized for resource</returns>
        private bool checkAuthorization(AuthorizationContext filterContext)
        {
            try
            {
                string actionName = filterContext.RouteData.Values["action"].ToString();
                string controllerName = filterContext.RouteData.Values["controller"].ToString();
                string username = filterContext.HttpContext.User.Identity.Name.Replace("DOMAIN\\", "");

                // we may check for authorization from Active Directory, LDAP or Database
                // lets use database for demo
                var db = new Data.AppDataContext();

                var oAuth = db.Authorizations.Where(a => a.Username.Equals(username) && a.Control.Equals(controllerName) && a.Action.Equals(actionName)).FirstOrDefault();
                if (oAuth != null)
                {
                    // if the user role satisfies one of the authorization role specified for the action then he/she is authorized
                    string[] arrRoles = this.Roles.Split(',');
                    if (arrRoles.Contains(oAuth.Role))
                        return true;
                }
            }
            catch (System.Exception e)
            {
                // handle the exception
            }
            return false;
        }
    }
}

If the user is unauthorized for the resource, the view for unauthorized access will be displayed.
Therefore we need a view for unauthorized access:

File: Views/Shared/UnAuthorized.cshtml

@{
    ViewBag.Title = "Unauthorized Access";
}
<h2>@ViewBag.Title</h2>

@ViewData["Message"]

That's it for filter based authorization.
Authorization using the AuthorizeAppAttribute filter should be as follows:

using System.Web.Mvc;
using Utils;
namespace FilterBasedAuthorization.Controllers
{
    // we may set authorization at controller level
    //[AuthorizeApp(Roles = "Staff")]
    public class SampleController : Controller
    {
        // no authorization
        public ActionResult Index()
        {
            return View();
        }

        // or we may set authorization at action level
        [AuthorizeApp(Roles = "Admin, Manager, Staff")]
        public ActionResult StaffIndex()
        {
            return View();
        }

        [AuthorizeApp(Roles = "Manager")]
        public ActionResult ManagerIndex()
        {
            return View();
        }
    }
}



Comments

Popular posts from this blog

Custom ActionResult for Files in ASP.NET MVC - ExcelResult

Platform independent simple password manager application (Electron & NodeJS)

Filtering html select listbox items