SiteMap dan User Role pada ASP.Net MVC

Pada ASP.Net MVC kita bisa menyembunyikan menu/node tertentu pada sitemap beradasarkan user role. Tambahkan roles pada existing sitemapnode kita seperti di bawah ini. Jika kita multiple role gunakan “,” sebagai pemisah.

<mvcSiteMapNode title="Vehicle Index" key="VehicleIndex" controller="Vehicle" action="Index" visibility="false" roles="Admin, Accountant"/>

kemudian buatlah Customer provider untuk mengoverride visibility dari sitemapnode tersebut.

public class SiteMapVisibilityCustomProvider : MvcSiteMapProvider.SiteMapNodeVisibilityProviderBase
    {
        private bool IsInRole(ISiteMapNode node)
        {
            if (HttpContext.Current == null)
               return true;
            if (HttpContext.Current.User == null)
                return true;

            if(node.Roles.Count == 0)
                return true;
            var IsInRole = false;
            foreach(var role in node.Roles)
            {
                IsInRole = HttpContext.Current.User.IsInRole(role);
                if (IsInRole)
                    break;

            }
            return IsInRole;
        }
        public override bool IsVisible(ISiteMapNode node, IDictionary<string, object> sourceMetadata)
        {
            if (node == null)
            {
                return true;
            }
            
            // Is a visibility attribute specified?
            object visibilityValue = null;
            node.Attributes.TryGetValue("visibility", out visibilityValue);
            if (visibilityValue != null)
            {
                bool nodeVisible;
                string visibility = visibilityValue.ToString();

                if (bool.TryParse(visibility, out nodeVisible))
                {
                    return nodeVisible;
                }
            }
            else
            {
                //check user role
                return IsInRole(node);
            }
            return true;
        }
    }

Pada web config set default visibility provider ke class tersebut, value = {className}, {assemblyName}

<add key="MvcSiteMapProvider_DefaultSiteMapNodeVisibiltyProvider" value="Astral.MVC.Helpers.SiteMapVisibilityCustomProvider, Astral.MVC"/>    

Sekarang, bagaimana agar mencegah user mengakses secara langsung alamat url dari page tersebut? kita buat custom authorization attribute yang akan melewatkan key dari sitemapnode dan medirect url ke halaman tertentu jika role user tidak memiliki akses.

[AttributeUsageAttribute(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class SiteMapAuthorizeAttribute : AuthorizeAttribute
{
  public string Key { get; set; }

  public override void OnAuthorization(AuthorizationContext filterContext)
  {
    base.OnAuthorization(filterContext);
    ISiteMapNode siteMapNode = null;
    var siteMap = MvcSiteMapProvider.SiteMaps.Current;
    if (siteMap == null)
      return;
    siteMapNode = siteMap.FindSiteMapNodeFromKey(Key);
    if (siteMapNode == null)
      return;
    if (siteMapNode.Roles.Count == 0)
      return;

    var IsInRole = false;
    foreach (var role in siteMapNode.Roles)
    {
      IsInRole = filterContext.HttpContext.User.IsInRole(role);
      if (IsInRole)
        break;
     }
     if (!IsInRole)
     {
        HandleUnauthorizedRequest(filterContext);
     }

}

//Called when access is denied
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{

//User isn't logged in
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
  filterContext.Result = new RedirectToRouteResult(
   new RouteValueDictionary(new { controller = "Account", action = "Login" })
  );
}
//User is logged in but has no access
else
{
  filterContext.Result = new RedirectToRouteResult(
  new RouteValueDictionary(new { controller = "Home", action = "Index" })
  );
}
}

Cara penggunaan attribute ini di controller action seperti ini.

[SiteMapAuthorize(Key ="VehicleIndex")]
public ActionResult Index()
{
}

Atau dengan cara lebih praktis, dimanage pada BaseController seperti ini

private void CheckAuthorization(ActionExecutingContext filterContext, string currentPageUrl)
      {
          ISiteMapNode siteMapNode = null;
          var siteMap = MvcSiteMapProvider.SiteMaps.Current;
          if (siteMap == null)
              return;
          siteMapNode = siteMap.FindSiteMapNode(currentPageUrl);
          if (siteMapNode == null)
              return;
          if (siteMapNode.Roles.Count == 0)
              return;

          var IsInRole = false;
          foreach (var role in siteMapNode.Roles)
          {
              IsInRole = filterContext.HttpContext.User.IsInRole(role);
              if (IsInRole)
                  break;
          }
          if (!IsInRole)
          {
              filterContext.Result = new RedirectToRouteResult(
                       new RouteValueDictionary(new { controller = "User", action = "Unauthorized" })
               );
          }
      }

private string GetPageUrl(ActionExecutingContext filterContext)
        {
            string controllerName = filterContext.Controller.GetType().Name;
            controllerName = controllerName.Substring(0, controllerName.Length - 10);

            string actionName = filterContext.ActionDescriptor.ActionName;
            return string.Format("/{0}/{1}", controllerName, actionName);

        }

override OnActionExecuting pada BaseController seperti ini.

protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            base.OnActionExecuting(filterContext);
            var currentPageUrl = GetPageUrl(filterContext);
             CheckAuthorization(filterContext, currentPageUrl);
        }
Iklan

Tinggalkan Balasan

Isikan data di bawah atau klik salah satu ikon untuk log in:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout /  Ubah )

Foto Google

You are commenting using your Google account. Logout /  Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout /  Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout /  Ubah )

Connecting to %s