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

时间:2022-12-18 20:53:04

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:

MVC Dynamic Authorization--示例市在Action前进行的验证,应提前到Auth过滤器 Collapse | Copy Code
[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.

MVC Dynamic Authorization--示例市在Action前进行的验证,应提前到Auth过滤器 Collapse | Copy Code
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