65.9K
CodeProject is changing. Read more.
Home

Permissions and Levels in ASP:Menu

Apr 15, 2012

CPOL

3 min read

viewsIcon

47630

downloadIcon

2348

Setting permissions to certain menuitems according to logged in user on the fly.

Introduction

In my last article I had discussed how to generate a menu dynamically from the database. In this article you will see how to generate a menu with two or more levels and deny access to certain menu items at runtime based on user permissions set by the administrator.

So let's design a multiple level menu first and for that we need to keep in mind two things:

  1. The ValuePath of the MenuItem, and
  2. The MaximumDynamicDisplayLevels property of the Menu control.

The ValuePath  

The ValuePath property contains the location of a particular menu item with respect to its parents, their parents, and so on, e.g., consider the following screenshot:

 

If the Value property of the MenuItems are as follows:  

MenuItem	Value
ParentItem1	p1
SubMenuItem2	s1
SubSubItem1	ss1
SSubItem1	sss1

Then the value path of the above MenuItems would be as follows:

MenuItem	ValuePath
ParentItem1	p1
SubMenuItem2	p1/s1
SubSubItem1	p1/s1/ss1
SSubItem1	p1/s1/ss1/sss1

The getValuePath function in the attached code calculates and returns the valuepath of a MenuItem using its assigned MenuID and MenuItemCollection from the database:

private string getValuePath(Int32 Parent, DataTable dt)
{
    int predecessor = Parent;
    StringBuilder valuePath = new StringBuilder();
    valuePath.Append(Parent.ToString());
    DataRow[] drPar;
    while (true)
    {
        drPar = dt.Select("MenuID=" + predecessor);
        if (drPar[0]["ParentID"].ToString().Equals("0"))
            break;
        valuePath.Insert(0,'/');
        valuePath.Insert(0,drPar[0]["ParentID"].ToString());
        predecessor = Convert.ToInt32(drPar[0]["ParentID"].ToString());
    }
    return valuePath.ToString();
}

Menu Levels

You can control the Maximum Display Levels (i.e., Menu Depth) of the Menu by adding a Line in the Page_load event of the master page when !IsPostBack, like:

menuBar.MaximumDynamicDisplayLevels = 3;
Menu Levels in Action:
  1. When we set it to 1
  2. menuBar.MaximumDynamicDisplayLevels = 1;

  3. And when we set it to 2:
  4. 	menuBar.MaximumDynamicDisplayLevels = 2;

    As you can see, the display levels of a menu depend on the user-setting irrespective of how much levels you have created in the database.

Creating a menu with multiple levels

To generate a Menu with more than one levels you would need to know the valuepath of the MenuItem to whom you are going to add a child. The following code snippet is the replacement of the getMenu() function used in the previous article:

foreach (DataRow dr in dt.Select("ParentID >" + 0))
{
    MenuItem mnu = new MenuItem(dr["MenuName"].ToString(), dr["MenuID"].ToString(),
	"", dr["MenuLocation"].ToString());

    //Code for Multiple Menu Levels
    string valuePath = getValuePath(Convert.ToInt32(dr["ParentID"].ToString()),dt);
    menuBar.FindItem(valuePath).ChildItems.Add(mnu);
    //End Code for Multiple Menu Levels
}

The first line enclosed in comments gets the ValuePath of a MenuItem.

While the second line uses this retrieved ValuePath to find the MenuItem from MenuItemsCollection and adds the MenuItem mnu to it as child.

Breakpoint: So till now we have created a menu with more than just one level and now we will assign permissions to the menu items by referring userpermissions from database. 

Menu Permissions

Before going further I must tell you that I have stored the permissions as string under a column named permissions in the user table in following format

1-11-12-

where menu IDs that are allowed for the corresponding user are separated by '-'.

Applying Permissions of a user to the menu is pretty simple.

Step 1: Retrieve the permissions string from database using the getUserPermissions(string username) function and split the returned string into an array of permitted MenuIDs

if (Session["username"] == null)
{
    return;
}
String[] permissions = getUserPermissions(Session["username"].ToString()).Split('-');

Here the getUserPermissions(string username) function takes logged in username as its argument and returns the corresponding permissions string which is then split at '-'s and stored inside an string array.

Step 2: Now that you have at hand the permissions, just toggle the MenuItem.Enabled property of sub menu items from inside the loop that adds submenu items, according to its presence in the permissions array.

if (!permissions.Contains(dr["MenuID"].ToString()))
{
      mnu.Enabled = false;
      mnu.ImageUrl = "denied.png";
}
else
{
      mnu.Enabled = true;
}

That's it, done. Below is a screenshot that shows a menu that is shown to a user who has some restrictions

Url Validation

You may ask what if the user directly types the url in the address bar and opens the page, not bothering whether the menuitem referring to that page is disabled or not. In that case the method validateurl(string url) that I have designed to check whether the page url being addressed is permitted or not.

...
DataRow[] drValidUrl = dt.Select("MenuLocation like '%" + url + "%'");
if (!(drValidUrl.Length == 0))
{
    String[] permissions = getUserPermissions(Session["username"].ToString()).Split('-');
    if (!permissions.Contains(drValidUrl[0]["MenuID"].ToString()))
    {
        Response.Redirect("~/Denied.htm");
    }
}
...

The above snippet is a portion of the validateurl(string url) method that takes as its argument the absolute path of the URL being requested.

this.Request.Url.AbsolutePath
and checks whether the URLs corresponding menu ID is present in the permissions array or not. If not then the user is greeted with following page..

Using the code

  1. In the attached source code I have provided a page named UserPermissions.aspx which you can use to assign permissions with ease.
  2. I have kept the database structures and sample data from tables for reference.