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();
}