Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Asp.Net MVC 2 is there a better way to return 401 status codes without getting an auth redirect

I have a portion of my site that has a lightweight xml/json REST API. Most of my site is behind forms auth but only some of my API actions require authentication.

I have a custom AuthorizeAttribute for my API that I use to check for certain permissions and when it fails it results in a 401. All is good, except since I'm using forms auth, Asp.net conveniently converts that into a 302 redirect to my login page.

I've seen some previous questions that seem a bit hackish to either return a 403 instead or to put some logic in the global.asax protected void Application_EndRequest() that will essentially convert 302 to 401 where it meets whatever criteria.

  • Previous Question
  • Previous Question 2

What I'm doing now is sort of like one of the questions, but instead of checking the Application_EndRequest() for a 302 I make my authorize attribute return 666 which indicates to me that I need to set this to a 401.

Here is my code:

protected void Application_EndRequest()
{
  if (Context.Response.StatusCode == MyAuthAttribute.AUTHORIZATION_FAILED_STATUS)
   {   
       //check for 666 - status code of hidden 401
        Context.Response.StatusCode = 401;
    }
 }

Even though this works, my question is there something in Asp.net MVC 2 that would prevent me from having to do this? Or, in general is there a better way? I would think this would come up a lot for anyone doing REST api's or just people that do ajax requests in their controllers. The last thing you want is to do a request and get the content of a login page instead of json.

like image 639
Greg Roberts Avatar asked May 12 '10 07:05

Greg Roberts


1 Answers

How about decorating your controller/actions with a custom filter:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class RequiresAuthenticationAttribute : FilterAttribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationContext filterContext)
    {
        var user = filterContext.HttpContext.User;
        if (!user.Identity.IsAuthenticated)
        {
            filterContext.HttpContext.Response.StatusCode = 401;
            filterContext.HttpContext.Response.End();
        }
    }
}

and in your controller:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    [RequiresAuthentication]
    public ActionResult AuthenticatedIndex()
    {
        return View();
    }
}
like image 190
Darin Dimitrov Avatar answered Sep 20 '22 19:09

Darin Dimitrov