The cookie limit of 4K is certainly an issue here when you have userData of size greater than 1K (actually 1200 bytes) because the FormsAuthentication API performs several operations that will expand your data size before it gets ready for packing inside a cookie.This operations like encoding in Hexa (size x 2) and the addition of some random entropy material, expands the userData size in a non linear way that it quickly reach this 4K limit. Unfortunately you won't notice what is really happening hence no exception is thrown. The only strange behavior is that Forms seems not to be working as expected. So beware of you userData size! (up to 1200 bytes length) (I know, it should have been documented).With that said, you still have room to store up to 50 roles of 23 bytes length each (character separator included). That’s a pretty good number of roles (IMO, if you have near that number of roles, perhaps you should review you authorization design model). If your needs of role storage exceeds this size, you should better use the traditional approach of an external DB store (mainly for performance and scalability reasons) and place on the “userData” parameter, some kind of ID that will give you a direct access to your role info. Another scenario might be a hybrid approach where you have some users that has just a few roles (under 50) and others users that has more than this limit (more than 50 roles!!, mmm… you should think about it). Here you might use a combination of the two models presented above.
Let’s see now a brief comparison between the MSDN samples and the suggested approach. The authentication and roles fetching are almost the same in both techniques. However, the main differences are in the cookie and the FormsAuthenticationTicket creation.Here we have this sample: (note: This code will be usually placed after the authentication and roles fetching code section. We assume that the variable ‘roles’ is a string array with all the user roles)
// Create the authentication ticketFormsAuthenticationTicket authTicket = new FormsAuthenticationTicket( 1, //version txtUserName.Text, // user name DateTime.Now, // creation DateTime.Now.AddMinutes(60),//Expiration false, //Persistent String.Join( "|", roles)); // User data
// Now encrypt the ticket.string encryptedTicket = FormsAuthentication.Encrypt(authTicket);// Create a cookie and add the encrypted ticket to the cookie as data.HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
// Add the cookie to the outgoing cookies collection.Response.Cookies.Add(authCookie);
// Redirect the user to the originally requested pageResponse.Redirect(FormsAuthentication.GetRedirectUrl(txtUserName.Text, false));
Compare with the proposed approach:
| // Get the cookie created by the FormsAuthentication API // Notice that this cookie will have all the attributes according to // the ones in the config file setting. HttpCookie cookie = FormsAuthentication.GetAuthCookie( UserId.Text, false ); FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);|
// Store roles inside the Forms Ticket with all the attributes aligned with // the config Forms section. FormsAuthenticationTicket newticket = new FormsAuthenticationTicket( ticket.Version, ticket.Name, ticket.IssueDate, ticket.Expiration, ticket.IsPersistent, String.Join( "|", roles), ticket.CookiePath); // add the encrypted ticket to the cookie as data. cookie.Value = FormsAuthentication.Encrypt(newticket); // Update the outgoing cookies collection. Context.Response.Cookies.Set(cookie);
// Redirect the user to the originally requested page Response.Redirect( FormsAuthentication.GetRedirectUrl( newticket.Name, newticket.IsPersistent ) );
The main difference is that our approach takes all the Forms data (cookie and Ticket) from the already created Forms cookie and Forms ticket so these two objects will be already filled with the setting of the Forms config section. This is crucial in order to get an easy configuration management from one place (the web.config file). The MSDN sample hardcode many of these settings so you won’t be able to control the Forms configuration like the proposed solution do.If you have a config section like the one below, with the MSDN sample you will loose many of the configured settings, specially those associated with the cookie (notice the requireSSL attribute ).
<authentication mode="Forms"> <forms loginUrl="Secure\login.aspx" protection="All" requireSSL="true" timeout="10" name="FormsAuthCookie" path="/FormsAuth" slidingExpiration="true" /> </authentication>
So with the proposed solution you will benefit from the performance gains by the roles caching inside the FormsAuthentication cookie (if you hopefully have less than 50 roles) and the configuration management from the web.config file only and not from “magic” values hardcoded inside your authentication method.