MVC Dynamic Authorization--示例市在Action前进行的验证,应提前到Auth过滤器

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: 

[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.

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

MVC Dynamic Authorization--示例市在Action前进行的验证,应提前到Auth过滤器,布布扣,bubuko.com

MVC Dynamic Authorization--示例市在Action前进行的验证,应提前到Auth过滤器

上一篇:利用AuthorizeAttribute属性简单避免 MVC 中的跨域攻击


下一篇:[转]模拟HttpContext 实现ASP.NET MVC 的单元测试