Forms authentication and role-based security: improving performance

Note: this entry has moved.

The usual approach to custom role-based security using forms authentication (i.e. roles and users fetched from a database) on web apps is the following:

protected void Application_AuthenticateRequest(Object sender, EventArgs e) { // Only replace the context if it has already been handled // by forms authentication module (user is authenticated) if (Context.Request.IsAuthenticated) { string roles[]; // Fetch roles from the database somehow. // Reuse the identity created by Forms authentication. GenericPrincipal ppal = new GenericPrincipal( Context.User.Identity, roles); Context.User = ppal; } }

There's one *huge* drawback to this approach, and it's that it will hit the database on every single request! So, the proposed improved solution is:

protected void Application_AuthenticateRequest(Object sender, EventArgs e) { if (Context.Request.IsAuthenticated) { // Retrieve user's identity from context user FormsIdentity ident = (FormsIdentity) Context.User.Identity; // Retrieve roles from the authentication ticket userdata field string[] roles = ident.Ticket.UserData.Split('|'); // If we didn't load the roles before, go to the DB if (roles[0].Length == 0) { // Fetch roles from the database somehow. // Store roles inside the Forms ticket. FormsAuthenticationTicket newticket = new FormsAuthenticationTicket( ident.Ticket.Version, ident.Ticket.Name, ident.Ticket.IssueDate, ident.Ticket.Expiration, ident.Ticket.IsPersistent, String.Join("|", roles), ident.Ticket.CookiePath); // Create the cookie. HttpCookie authCookie = new HttpCookie( FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(newticket)); authCookie.Path = FormsAuthentication.FormsCookiePath + "; HttpOnly; noScriptAccess"; authCookie.Secure = FormsAuthentication.RequireSSL; if (newticket.IsPersistent) authCookie.Expires = newticket.Expiration; Context.Response.Cookies.Add(authCookie); } // Create principal and attach to user Context.User = new System.Security.Principal.GenericPrincipal(ident, roles); } }

The new version only goes to the DB once. It also uses the same encryption features of forms authentication, as well as its ticket and cookie. A huge performance boost, that's for sure.

Thanks to Hernan for pointing this out while reviewing the security chapter of my last book.

Published 21 July 2004 03:28 PM by Daniel Cazzulino
Filed under: ,

Comments

No Comments