JuanDYB JuanDYB - 4 months ago 170
Ajax Question

Jquery Redirect inmediatly after Session Timeout

I have a web in ASP.NET MVC and I want to redirect to login page automatically after session timeout without the user intervention. For example like gmail does.

Now I'm doing ajax calls to the controller to check session in intervals of 5 seconds.

[HttpPost]
public JsonResult CheckSession(string currentUrl)
{
bool result = false;
Uri url = new Uri(currentUrl);
if (PublicUrl.Contains(url.AbsolutePath))
{
result = true;
}
else
{
result = HttpContext.User.Identity.IsAuthenticated;
}
return Json(result);
}


And if the result is false I do a redirect on JQuery.

This works well if I manually delete the cookies on the browser. But the problem is that the session never expires because I'm doing calls to server each 5 seconds so the session timeout resets on every server side call.

How can I redirect on Session expiry automatically?

Answer

There are several separate concerns here: server session timeout, and client side awareness of server session timeout, and doing something on user inactivity.

1) How you implementing session timeout on the server side?
2) Since you are keeping the session alive with your heartbeat (every 5 seconds) you probably never reach session timeout on the server.

You can manage this on the client side only, by making a logout call with JavaScript once the timeout value is reached. Use window.setTimeout() to set the inactivity timeout on the client side. When the timer fires, redirect the browser to either the logout controller, or a sessionExpired controller (your choice). Clear the timer using the beforeUnload event, and set a new one on page load.

Then, let the server timeout value deal with the case where the user closes browser and heartbeat stops.

Excerpt from web.config that defines my session timeout to 20 minutes:

  <authentication mode="Forms">
      <forms loginUrl="~/Account/Login" timeout="20" slidingExpiration="true" protection="All" name="ilApp" requireSSL="false" defaultUrl="~/Account/Login" />
   </authentication>
   <sessionState timeout="20" />

And javascript code that I added to /Shared/_Layout.cshtml as this file is included in every page on my site:

    @* Redirect browser to session expiration page on timeout *@
    @{
        var authenticationSettings = System.Configuration.ConfigurationManager.GetSection("system.web/authentication") as System.Web.Configuration.AuthenticationSection;
    }
    <script type="text/javascript">
        $(document).ready(function () {
            function ilSessionTimeout() {
                window.location = '@Url.Action("SessionExpired", "Account", new { area = "" })';
            };
            function ilSessionTimeoutWarning() {
                $.jGrowl('You will be logged off soon due to inactivity.', { sticky: true, theme: 'growl-warning', header: 'Attention' });
            };
            // remember our timers so we can cancel when we unload this page and reset them on the next page load
            var g_pageTimer = window.setTimeout(ilSessionTimeout, @authenticationSettings.Forms.Timeout.TotalMilliseconds);
            var g_pageTimerWarning = window.setTimeout(ilSessionTimeoutWarning, Math.round(@authenticationSettings.Forms.Timeout.TotalMilliseconds*0.8));
            // clean up anything that needs cleaning before we leave this page
            window.onbeforeunload = function(e) {
                // clear the timers
                window.clearTimeout(g_pageTimer);
                window.clearTimeout(g_pageTimerWarning);
            };
        });
    </script>

This sets two timers, one for the session timeout period (based on the value defined in web.config) and a second one at 80% expiration to show a warning message using jGrowl. I keep a handle to both timers in javascript global variables (g_pageTimer*) for the unload event.

I hooked into window.onbeforeunload to make sure I cancel my timers when the page is about to change. Without this, the timeout is absolute a redirects to logout regardless of client-side activity.

When timeout timer fires, I redirect to a page on my site, /Account/SessionExpired that shows a message to the user and then completes the logoff. In my example, I am using ASP.Net Identity 2, but whatever you normally do during logoff, you do here.

    // 
    // GET: /Account/SessionExpired
    [AllowAnonymous]
    public ActionResult SessionExpired()
    {
        try
        {
            System.Web.HttpContext.Current.Session.RemoveAll(); // Remove all session variables that we used
            AuthenticationManager.SignOut();
        }
        catch
        {
            // do nothing
        }

        return View();
    }