Question

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?

Was it helpful?

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).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top