asp.net.net-3.5forms-authenticationasp.net-caching

Where to store .net user roles between page requests


I've got a web site that implements its own Forms based login, and creates an authentication cookie like this:

    FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, userID, DateTime.UtcNow, expiration, isPersistent, userFunctions);
    HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket));
    cookie.Expires = expiration;
    HttpContext.Current.Response.Cookies.Add(cookie);

The variable "userFunctions" contains a comma-separated list of roles that the user is a member of.

In my Global.asax file I'm retrieving those user functions in the following way:

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    if (HttpContext.Current.User != null)
    {
        if (HttpContext.Current.User.Identity.IsAuthenticated)
        {
            if (HttpContext.Current.User.Identity is FormsIdentity)
            {
                FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;

                string[] roles = id.Ticket.UserData.Split(',');
                HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(id, roles);
            }
        }
    }
}

All this is working great. Or it was until I had to change it for a whole new bunch of users. The problem with the new users is that the "userFunctions" variable can get really long, and is way too long to store in a cookie (that is limited in size to something like 4k).

I would change my code to store the "userFunctions" in session, but session is not available to Application_AuthenticateRequest. I could possibly store the data in the application cache (maybe in a key/value pair) but I hesitate to do that as the application cache doesn't seem the 'right' place to put this data.

I probably will end up putting it in the application cache, but before I do I thought I'd ask and see if anybody has a better alternative?


Solution

  • Given that I cannot use Session to store user roles (as I cannot retrieve them before Authorization has taken place), and I didn't want the expense of making a trip to the database on every page request, I ended up storing the roles in the Application Cache:

    protected void Application_AuthenticateRequest(object sender, EventArgs e)
    {
        if (HttpContext.Current.User != null)
        {
            if (HttpContext.Current.User.Identity.IsAuthenticated)
            {
                if (HttpContext.Current.User.Identity is FormsIdentity)
                {
                    FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
    
                    string[] roles;
                    string cachedRoles = (string)HttpContext.Current.Cache.Get("UserFunctions" + id.Name.ToLower());
                    if (cachedRoles == null)
                    {
                        // Reload UserFunctions and add back in to Cache.
    
                        cachedRoles = [...code to get UserFunctions from database...];
    
                        HttpContext.Current.Cache.Insert("UserFunctions" + id.Name.ToLower(), cachedRoles, null, System.Web.Caching.Cache.NoAbsoluteExpiration, new TimeSpan(0, 20, 0), System.Web.Caching.CacheItemPriority.NotRemovable, null);
    
                    }
    
                    roles = cachedRoles.Split(',');
    
                    HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(id, roles);
                }
            }
        }
    }
    

    It seems to work ok (though with limited testing so far).