Contents
Introduction
If you want to develop a web application which requires authentication or security features not included in the regular ASP.NET membership feature, you might decide to implement these features yourself. But it seems as if the first instinct of many ASP.NET MVC developers is to do this by customizing their Controllers, but I will share you a better way that uses an attribute for that. We can inherit a System.Web.Mvc.AuthorizeAttribute for do that. You can specifies that access to a controller or action method is restricted to users who meet the authorization requirement.
Background
For my case, I want to authorize the user by role with attribute and can be apply to a controller and action, in the normal case, there are many actions in the controller, I want to restrict the role for most of actions of this controller but only allow a few actions for access, so the ACL attribute need to support two parameters, one for the disallow role and the others for allow actions, we can use comma for split each allow actions and disallow roles as below:
index, edit, add...
Using the code
1. Create the ACL attribute. There are two parameters for set the allow or disallow user roles, so we need to define two variables in constructor:
public class AclAttribute : AuthorizeAttribute { string _notAllowRoles; string _allowActions; /// <summary> /// Set the ACL attribute for access right /// </summary> /// <param name="NotAllowRoles">Not allow roles, split with comma</param> /// <param name="AllowActions">Set the actions allow for the restrict roles</param> public AclAttribute(string NotAllowRoles, string AllowActions = null) { _notAllowRoles = NotAllowRoles; _allowActions = AllowActions; } public AclAttribute() : base() { } }
2. We need to implement the OnAuthorization for do your customizing authentication logic
public override void OnAuthorization(AuthorizationContext filterContext) { if (filterContext == null) { throw new ArgumentNullException("filterContext"); } //get the current action for check the accessright var currentAction = filterContext.RouteData.Values["Action"]; bool ignore = false; //check login status if (filterContext.HttpContext.Session["IsLogin"] == null && currentAction != null) { //get the current url for redirect after login filterContext.HttpContext.Session["ReturnAction"] = HttpContext.Current.Request.Url.AbsoluteUri; UrlHelper url = new UrlHelper(HttpContext.Current.Request.RequestContext); //if session timeout or lost, then clear all sessions filterContext.HttpContext.Session.Clear(); //redirect to the login page if session is timeout var redirectUrl = url.RouteUrl(new { Controller = "Home", Action = "Login" }); HttpContext.Current.Response.Redirect(redirectUrl); } //check the allow actions, if this is allow actions, then will ignore the access right checking if (!string.IsNullOrEmpty(_allowActions) && _allowActions.Contains(currentAction.ToString())) { ignore = true; } //if set not allow roles if (!string.IsNullOrEmpty(_notAllowRoles) && !ignore) { //if user not allow to access then will redirect to the denied page if (_notAllowRoles.Contains(filterContext.HttpContext.Session["UserRole"])) { filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Error", action = "AccessDenied" })); return; } } //this Roles is inerit AuthorizeAttribute, if set it then will be allow to access if (!string.IsNullOrEmpty(this.Roles)) { //check accessright by user role if ((!HasAccessRights(this.Roles, filterContext.HttpContext.Session["UserRole"])) && !ignore) { filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Error", action = "AccessDenied" })); } } /// <summary> /// Check the access rights whether is allow /// </summary> /// <param name="roles"></param> /// <param name="currUserRoles"></param> /// <returns></returns> private bool HasAccessRights(string roles, string currUserRoles) { if (string.IsNullOrEmpty(currUserRoles)) { return false; } var uRoles = roles.Split(','); foreach (var role in uRoles) { if (currUserRoles.Contains(role)) { return true; } } return false; } }
3. Use the ACL attribute in controller. As below, the Account
role user will only can access the Index
and View
actions:
[Acl("Account", AllowActions: "Index,View")] public class CirculationController : BaseController { public CirculationController() { } public ActionResult Index() { //do something... } public ActionResult AjaxHandler() { //do something... } public ActionResult View() { //do something... } public ActionResult Others() { //do something... } }