Thursday, 23 May 2013

Session Expiration in ASP.NET MVC

The other day a colleague of mine asked me for some help fixing a bug. The issue was that our web sessions are configured to last 30 minutes and after 30 minutes of inactivity ASP.NET should redirect the user back to the login page (in our case at least), but this was not happening in our latest ASP.NET MVC website. I wandered over to his screen and saw it for myself, it just let the request complete as usual, defying my understanding of how session expiration worked.

So I searched around and found out the following:

Authorization

In our case the session timeout and the forms authentication timeout are different: sessions timeout at 30 minutes while forms authentication can last much longer. So it seems that what ASP.NET MVC does by default (using the [Authorize] attribute) is to authorize the request coming in because that has not expired yet but a new session is set up for the user. This means that any previous data you had stored is missing which will no doubt affect the functionality of your website.

Solution

So how can we solve this? This solution is actually quite simple, a custom authorization attribute can be implemented which can both authorize and check the session. For example let’s assume that your session contains something which you know means that a user is logged in, for instance a user ID; that means you can write something like the following:

[AttributeUsage(
AttributeTargets.Class
| AttributeTargets.Method,
Inherited
= true,
AllowMultiple
= true
)]
public class CustomAuthorizeAttribute : AuthorizeAttribute
{

protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
}

// Authenticate the user using Forms Authentication
IPrincipal user = httpContext.User;
if (!user.Identity.IsAuthenticated)
{
return false;
}

// Now check that a new session has not been created, if we are missing
// some critical session variables then we assume that the session
// expired and do not allow the request to continue
if (httpContext.Session["UserId"] == null)
{
return false;
}

return true;
}
}

By applying this custom authorization attribute to your controllers/actions you will now be able to check both forms authentication and session expiration at the same time.

2 comments: