9

Ok. So I have an issue where I need to do some authorization checks inside the controller action.

There are authorization roles, but it can exist that someone has TypeOnePayment, but not TypeTwo

[Authorize(Roles = "TypeOnePayment;TypeTwoPayment")]
public ActionResult EnterRevenue(PaymentType payment)
{
    payment = "TypeOne"; // This exists for show only.
    var permission = string.Concat(payment,"Permission");
    if (!SecurityUtility.HasPermission(permission))
    {
        return View("Unauthorized", "Error");
    }
    return this.PartialView("_EnterRevenue");
}

But since this is returning the partial view, the "Error" screen only appears in the partial view portion of the page. Is there a way to redirect to an entirely new page?

EDIT: EnterRevenue is being retrieved through an ajax call. So just the html is being returned and it's being placed in the view it was called from.

ELepolt
  • 373
  • 2
  • 4
  • 16

3 Answers3

6

You can redirect to some other action :

public ActionResult EnterRevenue
{
    if (!SecurityUtility.HasPermission(permission))
    {
        return View("Unauthorized", "Error");
    }
    return RedirectToAction("NotAuthorized","Error");
}

Assume we have ErrorController with action NotAuthorized which returns normal View which displays you are not authorized to view this page.

If you need this check on every action, then you need to implement custom action filter attribute in which you will have to check if it is normal request redirect else return staus as json and redirect from client side. See asp.net mvc check if user is authorized before accessing page

Here is a chunk of code:

public class AuthorizationAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            string actionName = filterContext.ActionDescriptor.ActionName;
            string controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;


            if (filterContext != null)
            {
                HttpSessionStateBase objHttpSessionStateBase = filterContext.HttpContext.Session;
                var userSession = objHttpSessionStateBase["userId"];
                if (((userSession == null) && (!objHttpSessionStateBase.IsNewSession)) || (objHttpSessionStateBase.IsNewSession))
                {
                    objHttpSessionStateBase.RemoveAll();
                    objHttpSessionStateBase.Clear();
                    objHttpSessionStateBase.Abandon();
                    if (filterContext.HttpContext.Request.IsAjaxRequest())
                    {
                        filterContext.HttpContext.Response.StatusCode = 403;
                        filterContext.Result = new JsonResult { Data = "LogOut" };
                    }
                    else
                    {
                        filterContext.Result = new RedirectResult("~/Home/Index");
                    }

                }


                else
                {

                    if (!CheckAccessRight(actionName, controllerName))
                    {
                        string redirectUrl = string.Format("?returnUrl={0}", filterContext.HttpContext.Request.Url.PathAndQuery);

                        filterContext.HttpContext.Response.Redirect(FormsAuthentication.LoginUrl + redirectUrl, true);
                    }
                    else
                    {
                        base.OnActionExecuting(filterContext);
                    }
                }


            }

        }
 }

and use it on action like this:

[Authorization]
public ActionResult EnterRevenue
{
    return this.PartialView("_EnterRevenue");
}
Ehsan Sajjad
  • 61,834
  • 16
  • 105
  • 160
  • I may have worded this poorly. But the EnterRevenue is the partial view. So no matter what gets returned, it only shows up in the partial view space on the main view it's being called from. – ELepolt Oct 29 '14 at 19:01
  • how are you calling EventRevenue action? show that piece of code? – Ehsan Sajjad Oct 29 '14 at 19:02
  • Edited my post, but EnterRevenue is being retrieved through an ajax call. So just the html is being returned and it's being placed in the view it was called from. – ELepolt Oct 29 '14 at 19:09
  • So there's some possibly some poorly written requirements, but we have Authorization set up on these pages. But essentially we have many different payment types, so there needs to be an individual check for each one. I'll update the code accordingly. – ELepolt Oct 29 '14 at 19:12
  • yes you should clearly tell and add relevant code so that your post is not misunderstood – Ehsan Sajjad Oct 29 '14 at 19:14
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/63887/discussion-between-elepolt-and-ehsan-sajjad). – ELepolt Oct 29 '14 at 19:19
1

Or just use a standard redirect call. This should work everywhere (just don't do it inside of a using statement or it will throw an exception in the background):

Response.Redirect("/Account/Login?reason=NotAuthorised", true);                         
NickG
  • 9,315
  • 16
  • 75
  • 115
0

I think what you need can be boiled down to a way for the ajax call to behave differently based on what you are returning to it. The best I have found for doing this can be summarized as follows:

  • When you detect that you have no permission, add a model state error to your model.
  • Override the OnActionExecuted (Hopefully all your controllers inherit from a base one so you can do it in one place, if not it might be a good idea to implement that now). In the override, check if the request is ajax and model state is not valid (if you want you can check for the specific error you added in the action method), change the request status to a 4xx status.
  • In the OnFailure of your ajax call, you can redirect to the error page using javascript code.
JTMon
  • 3,189
  • 22
  • 24