This post originated from an RSS feed registered with .NET Buzz
by Eric Wise.
Original Post: ASP .NET :: Know Your Roles - Level 200
Feed Title: Eric Wise
Feed URL: /error.htm?aspxerrorpath=/blogs/eric.wise/rss.aspx
Feed Description: Business & .NET
Setting up role based security for a website is a Very Good Thing (tm)
if you require flexibility in security. Many organizations I've
come across in my career struggle with security because they use a
system based on user type instead of groups and roles. The
obvious flaw with user type is that over time you end up with a new
user that is a "hybrid" and then you either have to add a new type, or
adjust all the pages that reference the types which grants other users
priviliges they've never had.
The worst of all sins I've seen in this scenario is actually HARD
CODING the user's userid into the page logic. Messy! So I'm
going to show you a fairly simple way to handle role based security in
a Forms Authenticated application.
Step 1: Roles, Groups, and Users
First things first, we'll need a structure that allows us to define
application roles, define groups, assign roles to groups, and assign
users to groups. For the purposes of this exercise we'll set up
the database structure like so:
CREATE TABLE [dbo].[ApplicationRoles] (
[applicationRoleID] [int] IDENTITY (1, 1) NOT NULL ,
[roleName] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[roleDescr] [varchar] (200) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[SecurityGroupRoles] (
[assocID] [int] IDENTITY (1, 1) NOT NULL ,
[applicationRoleID] [int] NOT NULL ,
[securityGroupID] [int] NOT NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[SecurityGroupUsers] (
[assocID] [int] IDENTITY (1, 1) NOT NULL ,
[securityGroupID] [int] NOT NULL ,
[userID] [varchar] (25) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[SecurityGroups] (
[securityGroupID] [int] IDENTITY (1, 1) NOT NULL ,
[securityGroupName] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[securityGroupDescr] [varchar] (200) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
) ON [PRIMARY]
GO
Step 2: Setting up Forms Authentication In the Web.Config
You've seen it before, and here it is again. Simply edit your web.config as follows:
Step 3: Edit the global.asax
Now we have to set up the application to accept a list of roles and
assign them to the current user. We do this in the
authenticate_request method like so:
Sub Application_AuthenticateRequest(ByVal sender AsObject, ByVal e As EventArgs) Dim CookieName AsString = FormsAuthentication.FormsCookieName Dim authCookie As HttpCookie = Context.Request.Cookies(CookieName)
'Check for cookie If IsNothing(authCookie) ThenReturn
Dim authTicket As FormsAuthenticationTicket Try
authTicket = FormsAuthentication.Decrypt(authCookie.Value) Catch Return EndTry
If IsNothing(authTicket) Then 'Cookie failed to decrypt Return EndIf
Dim roles() AsString = authTicket.UserData.Split("|") Dim id AsNew FormsIdentity(authTicket) Dim principal AsNew System.Security.Principal.GenericPrincipal(id, roles)
Context.User = principal EndSub
Do notice that I split authentication ticket's UserData property.
Sadly this is a string property so we can submit a collection of role
objects so in your code somewhere you'll have to combine all your roles
into a delimited string.
Step 4: Login page ticket creation
The last step is to create the forms authentication ticket for a successful login. You do this like so:
Dim authTicket AsNew FormsAuthenticationTicket(1, loginUser.UserID, DateTime.Now, DateTime.Now.AddMinutes(30), False, loginUser.GetRoles()) Dim encryptedTicket AsString = FormsAuthentication.Encrypt(authTicket) Dim authCookie = New HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket)
Response.Cookies.Add(authCookie)
This does require Imports System.Web.Security. Don't fret over
loginUser, it's just a class that I had created. All you have to
do is swap that out with your userID and the GetRoles() should be your
delimited role string. The SQL I use to GetRoles() is as simple
as this:
SELECT roleName from ApplicationRoles WHERE ApplicationRoleID IN
(SELECT DISTINCT ApplicationRoleID FROM SecurityGroupUsers
INNER JOIN SecurityGroups ON SecurityGroupUsers.SecurityGroupID = SecurityGroups.SecurityGroupID
INNER JOIN SecurityGroupRoles ON SecurityGroups.SecurityGroupID = SecurityGroupRoles.SecurityGroupID
WHERE SecurityGroupUsers.UserID = @UserID)