Click here to Skip to main content
15,881,204 members
Articles / Web Development / ASP.NET
Tip/Trick

MVC Dynamic Authorization

Rate me:
Please Sign up or sign in to vote.
4.64/5 (9 votes)
14 Jul 2013CPOL 55K   21   5
A simple way to implement "Dynamic Authorization" with the ability to assign permissions for actions to roles or users.

Introduction

In MVC the default method to perform authorization is hard coding the "Authorize" attribute in the controllers, for each action, in this article I will explain a simple way to implement "Dynamic Authorization" with the ability to assign permissions for actions to roles or users.  

Using the code 

First I will explain my user authentication and role assigning model, I have used Forms Authentication this scenario, here is my sample login action: 

C#
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
    //sample data
    Dictionary<string, string> users = new Dictionary<string, string>();
    users.Add("admin", "admin-pass");
    
    string roles;

    if (users[model.UserName] == model.Password)
    {
        Session["User"] = model.UserName;
        roles = "admin;customer";                
        // put the roles of the user in the Session            
        Session["Roles"] = roles;

        HttpContext.Items.Add("roles", roles);

        //Let us now set the authentication cookie so that we can use that later.
        FormsAuthentication.SetAuthCookie(model.UserName, false);

        //Login successful lets put him to requested page
        string returnUrl = Request.QueryString["ReturnUrl"] as string;

        return RedirectToLocal(returnUrl);

        if (returnUrl != null)
        {
            Response.Redirect(returnUrl);
        }
        else
        {
            //no return URL specified so lets kick him to home page
            Response.Redirect("Default.aspx");
        }
    }
    else
    {
        // If we got this far, something failed, redisplay form
        ModelState.AddModelError("", 
          "The user name or password provided is incorrect");
        return View(model);
    }
}

All the actions that need authentication have to be loaded in a list, and also all of the roles and actions that each role has access to, I have put some sample code to simulate them "AllRoles" and "NeedAuthenticationActions". Then we need to create a base class for controllers in which I have overridden the OnActionExecuting method, in which the user will be authorized based on its current role and whether he/she has logged in or not, the action may also has no need to be authorized.

C#
public class ControllerBase : Controller
{
private string ActionKey;

//sample data for the roles of the application
Dictionary<string, List<string>> AllRoles = 
           new Dictionary<string, List<string>>();

protected void initRoles()
{
    AllRoles.Add("role1", new List<string>() { "Controller1-View", 
      "Controller1-Create", "Controller1-Edit", "Controller1-Delete" });
    AllRoles.Add("role2", new List<string>() { "Controller1-View", "Controller1-Create" });
    AllRoles.Add("role3", new List<string>() { "Controller1-View" });
}
//sample data for the pages that need authorization
List<string> NeedAuthenticationActions = 
  new List<string>() { "Controller1-Edit", "Controller1-Delete"};  


protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
    ActionKey = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName +
                       "-" + filterContext.ActionDescriptor.ActionName;
                
    string role = Session["Roles"].ToString();//getting the current role
    if (NeedAuthenticationActions.Any(s => s.Equals(ActionKey, StringComparison.OrdinalIgnoreCase)))
    {
        if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            string redirectUrl = string.Format("?returnUrl={0}", 
                    filterContext.HttpContext.Request.Url.PathAndQuery);
            filterContext.HttpContext.Response.Redirect(FormsAuthentication.LoginUrl + redirectUrl, true);
        }
        else //check role
        {
            if (!AllRoles[role].Contains(ActionKey))
            {
                filterContext.HttpContext.Response.Redirect("~/NoAccess", true);
            }
        }
    }
}

Points of Interest

Using this scenario there is no need to hard code the Authorize attribute and role or user names in the controller class, and all of them may be loaded from any source and be used dynamically.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Iran (Islamic Republic of) Iran (Islamic Republic of)
I hold a BS degree in software engineering and am a Microsoft Certified Solution Developer(MCSD).
I have more than 8 years of experience in .NET developement, mostly web develop using C# and ASP.NET.

Comments and Discussions

 
QuestionGood Article need source code Pin
LogicPlayer18-Mar-17 6:11
LogicPlayer18-Mar-17 6:11 
AnswerRe: Good Article need source code Pin
Bahram Ettehadieh3-Apr-17 4:45
Bahram Ettehadieh3-Apr-17 4:45 
GeneralRe: Good Article need source code Pin
LogicPlayer25-May-17 19:31
LogicPlayer25-May-17 19:31 
Questioncomment Pin
d.Ramezani19-Oct-13 22:27
d.Ramezani19-Oct-13 22:27 
GeneralMy vote of 5 Pin
AlirezaZahediKermani28-Jul-13 4:55
AlirezaZahediKermani28-Jul-13 4:55 
راه خیلی خوبی بود. ممنون

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.