Search code examples
c#asp.netasp.net-mvcforms-authenticationsession-management

Session Manager will not log me out when session expires, HTTPContext.Current is Null


I'm having this issue with my current session manager, when the session expires it will not log off the user.

At random intervals while user is logged in the HttpContext.Current is NULL causing the site to generate many errors. I've tried a couple of techniques to redirect user to login upon session expiration, with no success.

  1. Under Global.asax I'm making use of Session_End can attempted to call LogOut method but this gets executed even before user logs in.
  2. Under Global.asax I added Application_AcquireRequestState, but sadly this makes way to many calls to the SSO Service. Also, it never redirected to login upon session expiration. I tested it with the following FormsAuthentication.RedirectToLoginPage(); No luck.

I found this answer by Lex Li "Why HttpContext.Current be null?" - it gave me some insight on what my problem could be, even-though my application doesn't make use of background-threads, my HttpContext.Current comes back Null with some random requests, doesn't always happen.

Session Manager

   public class SessionManager
    {
        private const string SessionKey = "AppSession";

        private SessionManager()
        {
            GUID                  = new Guid();
            FirstName             = String.Empty;
            LastName              = String.Empty;
            Email                 = String.Empty;
            SessionExpiration     = new DateTime();
        }

        // Gets the current session.
        public static SessionManager Current
        {
            get
            {
                if(HttpContext.Current != null)
                {
                    if (HttpContext.Current.Session[SessionKey] == null)
                    {
                        var model = new SessionManager();
                        HttpContext.Current.Session[SessionKey] = model;
                    }
                    return (SessionManager)HttpContext.Current.Session[SessionKey];
                }
                else
                {
                    return null;
                }
            }

        }

        public static void LogOffUser()
        {
            //SSO is a seperate service, I need to stay insync.
            var ssoAuth = new SSOAuth(); 
            if(Current != null)
               ssoAuth.SSOLogoffUser(Current.GUID);

            FormsAuthentication.SignOut();  
            FormsAuthentication.RedirectToLoginPage();
        }

        public Guid GUID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Email { get; set; }
        public DateTime SessionExpiration { get; set; }
    }

Login Controller

[HttpPost]
[AllowAnonymous]
public JsonResult Login(LoginViewModel user)
{
    var ssoAuth = new SSOAuth();
    var sessionObject = ssoAuth.SSOLoginUser(user.Email, user.Password);

    if (sessionObject != null && sessionObject.SessionId != Guid.Empty)
    {
        SessionManager.Current.Email                 = sessionObject.UserId;
        SessionManager.Current.GUID                  = sessionObject.SessionId;
        SessionManager.Current.FirstName             = sessionObject.FirstName;
        SessionManager.Current.LastName              = sessionObject.LastName;
        SessionManager.Current.SessionExpiration     = sessionObject.SessionExpiration;

        //Grab difference in time to get session timeout in minutes.
        var differenceInTime = SessionManager.Current.SessionExpiration - DateTime.Now;
        Session.Timeout = differenceInTime.Minutes;

        //Authenticate user
        FormsAuthentication.SetAuthCookie(user.Email, false);

        //We return JSON, Its an AJAX Call.
        return Json(new
        {
            redirectUrl = "/Home.mvc/Home/Index",
            isRedirect = true
        });
    }

    return Json(new
    {
        redirectUrl = string.Empty,
        isRedirect = false
    });
}

Solution

  • This sounds suspiciously like it may be a session vs. forms authentication timing issue similar to Forms Authentication Timeout vs Session Timeout

    Make sure your Forms timeout is at least 2x your session timeout.