1
votes

Iam working on an asp.net mvc4 web application, and I have the following action filter class, which implement a custom authorization :-

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]

    public class CheckUserPermissionsAttribute : ActionFilterAttribute
    {

        public string Model { get; set; }
        public string Action { get; set; }

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            // var user = User.Identity.Name; // or get from DB
            int value = 0;
            Repository repository = new Repository();

            if (!repository.can(ADusername,Model,value )) // implement this method based on your tables and logic
            {if (filterContext.HttpContext.Request.IsAjaxRequest())
                {

                    var viewResult = new JsonResult();
                    viewResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
                    viewResult.Data = (new { IsSuccess = "Unauthorized", description = "Sorry, you do not have the required permission to perform this action." });
                    filterContext.Result = viewResult;
               }
                else
                {
                    var viewResult = new ViewResult();

                    viewResult.ViewName = "~/Views/Errors/_Unauthorized.cshtml";
                    filterContext.Result = viewResult;
                }

            }

            base.OnActionExecuting(filterContext);
        }
    }
}

and i am using the actino filter before calling the action methods as follow:-

[CheckUserPermissions(Action = "Edit", Model = "Router")]
        public ActionResult Create(int? rackid)
        {

but i need to chnage the action filter class , to be a class that is driven from the AuthorizeAttribute , so can anyone advice what are the needed steps to do so ?

EDIT

I modified my action filter class to use AuthorizeAttribute as follow, but my previous caching problem still happening. as if an authorized user access an action method, then if unauthorized user access the same action method he will be able to read the cached data which he does not have permission on it .... and this was the reson i want to change my action filter to be an authorized attribute. my current authorized attribute is :-

public class CheckUserPermissionsAttribute : AuthorizeAttribute
    {

        public string Model { get; set; }
        public string Action { get; set; }

        public override void OnAuthorization(AuthorizationContext filterContext)
        {

         // code goes here
            if (!repository.can(ADusername,Model,value )) // implement this method based on your tables and logic
            {
               // filterContext.Result = new HttpUnauthorizedResult("You cannot access this page");

                if (filterContext.HttpContext.Request.IsAjaxRequest())
                {

                    var viewResult = new JsonResult();
                    viewResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
                    viewResult.Data = (new { IsSuccess = "Unauthorized", description = "Sorry, you do not have the required permission to perform this action." });
                    filterContext.Result = viewResult;
                //    filterContext.HttpContext.Response.StatusCode = 400;

                    //filterContext.Result = new HttpUnauthorizedResult("You cannot access this page");

                }
                else
                {
                    var viewResult = new ViewResult();

                    viewResult.ViewName = "~/Views/Errors/_Unauthorized.cshtml";
                    filterContext.Result = viewResult;
                }

            }

            base.OnAuthorization(filterContext);
        }
    }
}

so is my current approach valid ?, baring in mind that i am returning unauthorized view or JSON based on the request type , instead of returning 401 http response ?

Thanks

1

1 Answers

2
votes

Something like this:

public class CheckUserPermissionsAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        bool authorized = /* your logic here */;

        if (!authorized) 
            base.HandleUnauthorizedRequest(filterContext);
    }
}

Now, to configure the custom error page ("Unauthorized"), here's what you'd probably need inside your web.config file:

<system.webServer>
    <httpErrors errorMode="Custom" existingResponse="Replace">
        <remove statusCode="403" subStatusCode="-1" />
        <error statusCode="403" path="/error/403" responseMode="ExecuteURL" />
    </httpErrors>
</system.webServer>

Now, the routing:

routes.Add("Error", new Route("error/{statusCode}",
    new { controller = "Error", action = "Details" }));

And finally, the controller:

public class ErrorController : Controller
{
    public ActionResult Details(int statusCode)
    {
        return View(new { StatusCode = statusCode });
    }
}

Couple of links to study:

Hope this helps.