Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to intercept 401 from Forms Authentication in ASP.NET MVC?

I would like to generate a 401 page if the user does not have the right permission.

The user requests a url and is redirected to the login page (I have deny all anonymous in web.config). The user logs in successfully and is redirected to the original url. However, upon permission check, it is determined that the user does not have the required permission, so I would like to generate a 401. But Forms Authentication always handles 401 and redirects the user to the login page.

To me, this isn't correct. The user has already authenticated, the user just does not have the proper authorization.

In other scenarios, such as in ajax or REST service scenario, I definitely do not want the login page - I need the proper 401 page.

So far, I've tried custom Authorize filter to return ViewResult with 401 but didn't work. I then tried a normal Action Filter, overriding OnActionExecuting, which did not work either.

What I was able to do is handle an event in global.asax, PostRequestHandlerExecute, and check for the permission then write out directly to response:

if (permissionDenied)
{
    Context.Response.StatusCode = 401;
    Context.Response.Clear();
    Context.Response.Write("Permission Denied");
    Context.Response.Flush();
    Context.Response.Close();
    return;
}

That works but it's not really what I want. First of all, I'm not even sure if that is the right event or the place in the pipeline to do that. Second, I want the 401 page to have a little more content. Preferably, it should be an aspx page with possibly the same master page as the rest of the site. That way, anyone browsing the site can see that the permission is denied but with the same look and feel, etc. but the ajax or service user will get the proper status code to act on.

Any idea how this can be achieved? I've seen other posts with similar requests but didn't see a solution that I can use.

And no, I do not want a 403.

like image 743
Jiho Han Avatar asked May 28 '10 19:05

Jiho Han


Video Answer


2 Answers

I found a workable solution.

401 redirect by FormsAuthenticationModule occurs during EndRequest. Since during event processing Modules are invoked before global.asax, we can override the status code after FormsAuthenticationModule has had its grubby hands on the request.

In my custom AuthorizationFilter, I set HttpContext.Items["PermissionDenied"] to true and then in my global.asax EndRequest, I flip the status code from 200 to 401. Then I Server.Transfer to my custom PermissionDenied view.

I would still prefer FormsAuthenticationModule itself was updated to handle this scenario but I think this is not too hackish that I think I can live with it.

Obviously, you can change how you signal that global.asax should flip the status code. I just tried setting the status code to something like 511 and used that as the condition rather than HttpContext.Items and that worked as well. I guess as long the proper status code goes out the door, the ASP.NET engine doesn't care.

like image 60
Jiho Han Avatar answered Oct 02 '22 00:10

Jiho Han


HttpContext.Current.Response.SuppressFormsAuthenticationRedirect = true;
like image 35
ulu Avatar answered Oct 01 '22 23:10

ulu