Authenticated web services calls with Asp.Net MVC
I’ve been encountering a problem as of late. I’m creating a lot of “Single Page Pattern” web applications. This means you load the page once, then handle everything else via web service calls.
And if you have ever worked on web applications you should be familiar with the “user went to lunch” issue (session timeout). User leaves for an hour, comes back to your web page, and expects it to continue working. Unfortunately the session timed out, and now you have to refresh a bunch o’ crap. Another version of the problem, the “.ASPXFORMSAUTH” cookies gets deleted. Either way, your web site stop just working and the user blames you.
The fix is to have the user log in again. Normally this is simple, when the user does something, then the page is refreshed and redirected to the login page (as assigned in the web.config). That is the standard web model. Unfortunately it does not work in this case.
Web services complicate things. When inside a web method request, redirects do not work, and even worse if you are using JQuery “load” method (which loads html directly into an element), then you get the login page inside of a div. But more often, your web client code is expecting JSON, and will be getting html (an error page or the login page).
So my current solution it to wrap up the JQuery AJAX methods with my own methods. This way I can check the users authentication (another web method). If I see the user is not logged in, I redirect to the login page. The other web method is killed via the page redirect.
Here is my wrapper:
1: var ajax = {
2: _lastAuthCheck: new Date().getTime(),
3: getJSON: function(url, data, callback) {
4: ajax.CheckAuthentication();
5: return $.getJSON(url, data, callback);
6: },
7: post: function(url, data, callback, type) {
8: ajax.CheckAuthentication();
9: return $.post(url, data, callback, type);
10: },
11: load: function(destination, url, params, callback) {
12: ajax.CheckAuthentication();
13: destination.load(url, params, callback);
14: },
15: CheckAuthentication: function() {
16: if (!TimeToCheckAuth()) return;
17: $.getJSON('<%=Url.Action("IsAuthenticated", "Account")%>', null, function(result) {
18: if (!result) {
19: window.location = '<%=Url.Action("LogOn", "Account")%>';
20: } else {
21: ajax._lastAuthCheck = new Date().getTime();
22: }
23: });
24:
25: function TimeToCheckAuth(){
26: var currentTime = new Date().getTime();
27: var diff = currentTime - ajax._lastAuthCheck;
28:
29: return (diff > 5000);
30: }
31: }
32: };
Now with the wrapper in place I switch my $.ajax, $.get, $.post calls to ajax.ajax, ajax.get, ajax.post. All the parameters should stay the same.
Notice one thing, I’m mixing in Url.Action calls in that code. I should add that this code is in a separate file for me, not in my web form page. If you want to get more of an idea of how I do that, check out my post on Asp.Net MVC JavaScriptView.
Now the web method, IsAuthenticated, is about as simple as you can get:
1: [AcceptGet]
2: public JsonResult IsAuthenticated()
3: {
4: return Json(User.Identity.IsAuthenticated);
5: }
But back to the JavaScript, there are a couple of other things going on here. First off, the authentication check will happen at the same time actual web method call. I banking on the theory that the authentication check will return before the other method. Second, I put an extra check in the method, so at most the authentication check will only happen once ever 5 seconds. Adjust as you feel necessary.


