I am working in an MVC project where user roles, and permissions for each of the action methods are stored in the database. What I want to achieve is to use the authorize filter feature in mvc by overriding AuthorizeAttribute. This way I can register my custom authorize filter globally.
Here is what I am trying to do, following this method. I am following this article to handle ajax requests.
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//Custom permission checking logic
return false;//no permission for all methods-Just for testing
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
CheckIfUserIsAuthenticated(filterContext);}
}
private void CheckIfUserIsAuthenticated(AuthorizationContext filterContext)
{
// If Result is null, we’re OK: the user is authenticated and authorized.
if (filterContext.Result == null)
return;
var httpContext = filterContext.HttpContext;
var request = httpContext.Request;
var response = httpContext.Response;
var user = httpContext.User;
// If here, you’re getting an HTTP 401 status code. In particular,
// filterContext.Result is of HttpUnauthorizedResult type. Check Ajax here.
if (request.IsAjaxRequest())
{
if (user.Identity.IsAuthenticated == false)
response.StatusCode = (int)HttpStatusCode.Unauthorized;//401
else
response.StatusCode = (int)HttpStatusCode.Forbidden;//403
response.SuppressFormsAuthenticationRedirect = true;
response.End();// This line is causing the problems
return;
}
if (user.Identity.IsAuthenticated)
{
//Redirect to customerror page
}
}
The issue is when I am calling a method using ajax post, my custom exception filter is catching an error saying "Server cannot set status after HTTP headers have been sent "
If I remove response.End(), I am getting a 401 response in the ajax error handler method instead of 403.
I tried
HttpContext.Current.ApplicationInstance.CompleteRequest()
instead of response.end, but then also I am getting 401 error
Is there anyway to avoid this exception?
Update I am using this general error handler method in javascript to catch all ajax request errors ( I need correct status code for response):
function ajaxFailed(xhr, textstatus, errorthrown) {
debugger;
if (textstatus == "error") {
if (xhr.status == 401) {
window.location = "/Account/Login";
}
if (xhr.status == 403) {
$("#divoutput").html("you don't have permission.");
}
}
if (xhr.status == 500) {
$("#divoutput").append("<br/> internal servererror." + xhr.responseText);
}
}
Update 2: My Current Solution: Check the Exception.Message property of the raised exception in my custom exception handler filter and ignore it if the message is :"Server cannot set status after HTTP headers have been sent ".
I know this is an inefficient method, but I have no other solution yet. Waiting for a good solution :)