ASP.NET Security Basics: Caching Roles

Just a quick “request” post covering the basics of caching user roles in an ASP.NET application using forms based authentication.

Role based authentication & authorisation is an important part of most modern web applications.  After successful authentication of a user, an authorisation process must take place to determine which areas of the application the user has access to.

To implement the basic role based security, there are three points to be considered. In this example we are returning a list of roles from a database for a particular user.

We can then add a web.config to each directory we wish to protect in the following format.

<authorization> <allow roles="role1,role2"></allow>
<deny users="*"></deny></authorization>

Application_AuthenticateRequest is defined in Global.asax and will be accessed each time a web request is made if your application. In order to save a database trip for each time you’re grabbing your roles, it’s best to use a cached mechanism for this:

   Try            If HttpContext.Current.User IsNot Nothing Then                If HttpContext.Current.User.Identity.IsAuthenticated Then                    If HttpContext.Current.User.Identity.AuthenticationType <> "Forms" Then                        Throw New Exception(String.Format("You attempted to authenticate with {0} but only forms authentication is accepted.", HttpContext.Current.User.Identity.AuthenticationType)                    End If                    Dim userId As System.Security.Principal.IIdentity = HttpContext.Current.User.Identity                    ' If the roles aren't in cache, do it now.                    If System.Web.HttpContext.Current.Cache(userId.Name) Is Nothing Then						' Just a simple example using a dataset!                        Dim dsRoles As DataSet = SomeStaticClass.GetRoles(User.Identity.Name) ' Get roles as a comma delimited string                        Dim roles As String() = New String(dsRoles.Tables(0).Rows.Count - 1) {}                        For row As Integer = 0 To dsRoles.Tables(0).Rows.Count - 1                            For col As Integer = 0 To dsRoles.Tables(0).Columns.Count - 1                                roles(row) = dsRoles.Tables(0).Rows(row)(col).ToString()                            Next                        Next                        ' Usually this information will be collected from a database.                                   ' One hour expiration time                        System.Web.HttpContext.Current.Cache.Add(userId.Name, roles, Nothing, DateTime.MaxValue, TimeSpan.FromHours(1), System.Web.Caching.CacheItemPriority.BelowNormal, _                         Nothing)                    End If                    'Assign the roles to the user in the current security context                    HttpContext.Current.User = New System.Security.Principal.GenericPrincipal(userId, DirectCast(System.Web.HttpContext.Current.Cache(userId.Name), String()))                End If            End If        Catch ex As Exception            Response.Redirect("/MyErrorPage")        End Try

Leave a Reply