0
votes

I am wanting to override the default behavior of the [Authorize] attribute. I found this similar question but it is very old and MVC has had a few iterations since it was published.

I would prefer not to create a separate 'custom' attribute class and apply that attribute on all controllers/actions in order to just send an unauthorized request to a separate controller/action. I would like to be able to do this globally and affect all the controllers/actions that are already configured with an [Authorize] attribute.

Is this possible?

1
No. By decorating your controller or action with Authorize, you are coupling it to the AuthorizeAttribute object. You can't edit that object's source, obviously, unless you want to build your own MVC assembly :) Your best bet is to derive from it and override the appropriate methods as detailed in that other post. - Mister Epic
Thanks @ChrisHardie! I have updated my post above with how I made this work using a custom attribute. - FrankO
FWIW, this is not AuthorizeAttribute. It returns a proper 403 response for authenticated users that still do not have access to a particular action. Forms Authentication is actually the culprit here. It intercepts both 401 (unauthenticated) and 403 (authenticated, but unauthorized) and redirects to the login page. There doesn't seem to be a way to stop that, either. You can manually disable the redirect within an action (ASP.NET 4.5+), before returning a 401 or 403, but not on a global basis and not for just one of the two status code. - Chris Pratt

1 Answers

1
votes

Ok. Since there isn't a way to overrride the [Authorize] attribute, globally and in place, here is how I got it done.

Create a new custom AuthorizeAttribute class in the global namespace for your application (I called mine CustomAuthorizeAttribute). I placed this class file in a folder called Extend (its where I put all my custom classes when extending the MVC framework) and made sure the namespace is the same as the root namespace for my application (this way all controllers can 'see' it).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace CustomProject
{
    public class CustomAuthorizeAttribute : AuthorizeAttribute
    {
        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            System.Web.Routing.RouteValueDictionary rd;
            if (filterContext.HttpContext.User.Identity.IsAuthenticated)
            {
                rd = new System.Web.Routing.RouteValueDictionary(new { action = "NotAuthorized", controller = "Error" });
            }
            else
            {
                //user is not authenticated
                rd = new System.Web.Routing.RouteValueDictionary(new { action = "Login", controller = "Account" });
            }
            filterContext.Result = new RedirectToRouteResult(rd);
        }
    }
}

My CustomAuthorizeAttribute takes into account authenticated user scenarios and reroutes/redirects appropriately.

You then need to add the [CustomAuthorize(Roles="Admin")] (use the roles that you have configured for your application) to your controllers and/or actions that you want to scrutinize.

In addition, I created an ErrorController to handle errors and added a "NotAuthorized" action for my needs. You can certainly extend this if you like. Maybe include some logging?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace HypeKick.BankUI.Controllers
{
    public class ErrorController : Controller
    {
        //
        // GET: /Error/
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult NotAuthorized()
        {
            return View();
        }
}
}

Don't forget to create the necessary views!