Friday 3 November 2017

Session Cookies expiration handling in ASP.NET MVC 3 while using WIF and jquery ajax requests

itemprop="text">

I my project I'm using WIF
(but this is not really important for the context of this question. You can
use alternative framework which handles your authentication. Question is about dealing
with authentication failures while performing ajax requests)
. Nevertheless,
in my case I've written custom server logic which inherits from
ClaimsAuthenticationManager, and handles
authentication:



public override
IClaimsPrincipal Authenticate(string resourceName, IClaimsPrincipal
incomingPrincipal)
{
if (incomingPrincipal != null &&
incomingPrincipal.Identity.IsAuthenticated)
{
// add some custom
claims
}

return
incomingPrincipal;
}


Now,
after I delete all Session Cookies, end then enter any page
again, I'm redirected to the login page served by WIF, and I'm requested to log again.
Everything works as expected.



But if I make an
ajax request instead, I've got an error, which is
intercepted by
this:



$(document).ready(function
() {
$.ajaxSetup({

error: function (XMLHttpRequest,
textStatus, errorThrown) {
// do something
}

});
});


Unfortunately
XMLHttpRequest object does not return any meaningful message,
based on which I could handle this kind of error in any other way as others. In this
particular case I just want application to redirect to the login page - as the normal
request does.



src="https://i.stack.imgur.com/hlb4H.jpg" alt="enter image description
here">




While the ajax call is
executing, the method Authenticate from
ClaimsAuthenticationManager is invoked.
Identity.IsAuthenticated returns false, method ends and all is
done. Even the OnAuthorization method from
BaseController is not invoked, so I cannot pass any status to
the ajax result object.



protected
override void OnAuthorization(AuthorizationContext filterContext)
{

if (filterContext.HttpContext.Request.IsAjaxRequest() &&
!User.Identity.IsAuthenticated)
{
//do something, for example pass
custom result to filterContext
}

base.OnAuthorization(filterContext);

}


How
to resolve the puzzle ?


itemprop="text">
class="normal">Answer



I've found
some resources about this (see bottom of the answer), and mixed up with following
solution:



while performing ajax request, I
specified that I want json back:



$.ajax({


url: action,
type: 'POST',
dataType: 'json',
data:
jsonString,
contentType: 'application/json; charset=utf-8',

success:
function (result, textStatus, xhr) {

}
});



Because
my framework handles authentication, while token expires, it puts http status 302 to the
response. Because I don't want my browser to handle 302 response transparently, I catch
it in Global.asax, and changed status to 200 OK. Aditionally, I've added header, which
instructs me to process such response in special
way:



protected void
Application_EndRequest()
{
if (Context.Response.StatusCode ==
302
&& (new
HttpContextWrapper(Context)).Request.IsAjaxRequest())
{

Context.Response.StatusCode = 200;

Context.Response.AddHeader("REQUIRES_AUTH", "1");


}
}


Response
content is not properly serialized to json, which results in parsing error. Error event
is invoked, inside which the redirection is
performed:



$(document).ready(function
() {
$.ajaxSetup({
error: function (XMLHttpRequest, textStatus,
errorThrown) {
if (XMLHttpRequest.getResponseHeader('REQUIRES_AUTH') === '1')
{

// redirect to logon page
window.location =
XMLHttpRequest.getResponseHeader('location');
}
// do sth
else
}

});
});


See
href="https://stackoverflow.com/questions/199099/how-to-manage-a-redirect-request-after-a-jquery-ajax-call">How
to manage a redirect request after a jQuery Ajax call and here href="https://stackoverflow.com/questions/6324590/how-do-you-deal-with-ajax-requests-when-user-session-expires-or-where-the-reque">How
do you deal with AJAX requests when user session expires, or where the request
terminates in a 302 for more
explanation.




UPDATE:



Meantime,
I figured out new solution, in my opinion much better,
because can be applied to all ajax requests out of the box (if they do not redefine
beforeSend event
obviously):



$.ajaxSetup({

beforeSend: checkPulse,
error: function (XMLHttpRequest, textStatus,
errorThrown) {
document.open();

document.write(XMLHttpRequest.responseText);


document.close();
}
});

function
checkPulse(XMLHttpRequest) {
var location = window.location.href;

$.ajax({
url: "/Controller/CheckPulse",
type: 'GET',

async: false,

beforeSend: null,
success:

function (result, textStatus, xhr) {
if
(xhr.getResponseHeader('REQUIRES_AUTH') === '1') {
XMLHttpRequest.abort(); //
terminate further ajax execution
window.location = location;

}
}

});
}



The
controller method can be anything
simplest:



[Authorize]
public
virtual void CheckPulse()
{}


The
Application_EndRequest() stays the same as
before.


No comments:

Post a Comment

php - file_get_contents shows unexpected output while reading a file

I want to output an inline jpg image as a base64 encoded string, however when I do this : $contents = file_get_contents($filename); print &q...