Friday, January 18, 2013

MVC4 Authroize Attribute

Most people know about authorize attribute and to customize also, but i had a request where i need to combine below elements 1. The roles will be from an external application 2. I wont know what action or controller they can perform 3. Do not want to code If statement to check the access on each controller 4. Want to make the make the connection of Role and action in the project 5. no usage of sessions So thought of a design 1. Have the role and controller action in web.config
 

    
      
    
        
        
              
    
          
        
              
    
  
2. using cutom configuration as below
 

using System;
using System.Collections;
using System.Text;
using System.Configuration;
using System.Xml;



namespace SomethingCommon
{

    public class RolesSection : ConfigurationSection
    {
        [ConfigurationProperty("", IsDefaultCollection = true)]
        public RoleElementCollection Elements
        {
            get { return (RoleElementCollection)base[""]; }
        }
    }

    public class RoleElementCollection : ConfigurationElementCollection
    {
        const string ELEMENT_NAME = "Role";

        public override ConfigurationElementCollectionType CollectionType
        {
            get { return ConfigurationElementCollectionType.BasicMap; }
        }

        protected override string ElementName
        {
            get { return ELEMENT_NAME; }
        }

        protected override ConfigurationElement CreateNewElement()
        {
            return new RoleElement();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((RoleElement)element).Name;
        }
    }

    public class RoleElement : ConfigurationElement
    {
        const string NAME = "name";

        [ConfigurationProperty(NAME, IsRequired = true)]
        public string Name
        {
            get { return (string)base[NAME]; }
        }

        [ConfigurationProperty("", IsDefaultCollection = true)]
        public ControllerActionElementCollection Elements
        {
            get { return (ControllerActionElementCollection)base[""]; }
        }
    }

    public class ControllerActionElementCollection : ConfigurationElementCollection
    {
        const string ELEMENT_NAME = "ControllerAction";

        public override ConfigurationElementCollectionType CollectionType
        {
            get { return ConfigurationElementCollectionType.BasicMap; }
        }

        protected override string ElementName
        {
            get { return ELEMENT_NAME; }
        }

        protected override ConfigurationElement CreateNewElement()
        {
            return new ControllerActionElement();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((ControllerActionElement)element).Id;
        }
    }

    public class ControllerActionElement : ConfigurationElement
    {
        const string ID = "id";

        [ConfigurationProperty(ID, IsRequired = true)]
        public string Id
        {
            get { return base[ID].ToString(); }
        }
    }


}
2. Have Security attributre in the controller
 
 [Security]
        public JsonResult GetSomething(string sidx, string sord, int page, int rows, string ID)
        {
3. ... Still thinking of cahing but check each controller
 


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;


namespace SomethingBLL
{
    public class SecurityAttribute : AuthorizeAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            base.OnAuthorization(filterContext);
      
             var wccSecurityList = from external system

            var securityList = wccSecurityList as IList ?? wccSecurityList.ToList();
         
            

            //find if the role allows to access the contoller action - if yes then allow , if not then error 
            var controllerAction = filterContext.Controller.ToString() + "-" + filterContext.ActionDescriptor.ActionName;

	
		// to chek
            var isAuthorized = ControllerActionRoles.CheckControllActionForRole(securityList, controllerAction);
                  
            if (!isAuthorized && filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated)
            {
                filterContext.Result = new RedirectToRouteResult(new
                                                                     RouteValueDictionary(
                                                                     new {controller = "Error", action = "AccessDenied"}));
            }
        }

    }
}

 




4. Code the combines the list and do the magic of checking . please remember the code has some things which i used in my project so it it just an idea ../. RolesSecurity is a model that has 2 string items from web.conifg


 private static List GetRoles()
        {
            var roleSecurityList = new List();
            var section = ConfigurationManager.GetSection("Roles");
            var RolesSection = ConfigurationManager.GetSection("Roles") as RolesSection;

           
            if (RolesSection != null)
            {

                roleSecurityList.AddRange(
                  RolesSection.Elements.Cast()
                                 .SelectMany(Role => Role.Elements.Cast(),
                                             (Role, controllerAction) => new RolesSecurity
                                             {
                                                 RoleName = Role.Name,
                                                 ControllerAction = controllerAction.Id
                                             }));
            }
            else
            {
                throw new Exception("Error");
            }

            return roleSecurityList;
        }


  public static bool CheckControllActionForRole(IList mstRole, string controllerAction)
        {
         
            //get the list from webconfig
            List controllerActionList = GetRoles();        
            var commonList = controllerActionList.Where(x => mstRole.Any(x1 => x1.ToString() == x.RoleName)).Where(x => x.ControllerAction == controllerAction);

            //get only the list for mstRole 
            // check if the controllaction from security is in controlleraction of webconfig
            return commonList.Any();
        }

No comments: