Question

In my Asp.NET C# application, I have a sitemap bound to a menu for site navigation. To control user access, I am using the NHibernate Custom Role Provider by Manuel Abadia, and setting the Roles attribute on each SiteMap node.

<siteMapNode title="Add/Modify Roles" description="Add/Modify User Roles"
url="~/MemberPages/Admin_Roles.aspx" roles="Administrator" />

Everything has been working fine so far, but now I wish to have several webpages that do not appear on the sitemap-bound menu, but still use the sitemap nodes to control user access. For example, I have a page exclusively for admins that displays all the Roles in the database (ViewPage). On that page, I have a 'Add New' button which redirects the user to another page to add a new Role (AddPage). ViewPage should exist on the menu, and AddPage shouldn't, but both should share the same access settings (only accessible by admins).

How should I go about achieving this? I am aware that I can declare the access settings in my web.config file, but I would rather avoid this as there will be many pages like this one. Also, system admins will be allowed to customize the access rules, like changing it from admin-only to admins & moderators, so it would be more convenient if the system could alter the access rules for all pages in one sitemap.

Was it helpful?

Solution

Thanks to MikeSmithDev's comment, I've managed to sort out a nice solution. If anyone else comes across the same problem, here's what I did:

In my SiteMap, I added a custom attribute HideFromMenu:

<siteMapNode title="Add Page" description="Page to Add stuff"
roles="Administrator" url="~/AddPage.aspx" HideFromMenu="true" />

In my Menu control, I added the OnMenuItemDataBound attribute:

<asp:Menu ID="Menu1" runat="server" DataSourceID="siteMapSource" 
OnMenuItemDataBound="Menu1_MenuItemDataBound" >

And in the master's code-behind:

protected void Menu1_MenuItemDataBound(object sender, MenuEventArgs e)
{
    SiteMapNode node = (SiteMapNode)e.Item.DataItem;
    if (node["HideFromMenu"] == "true")
    {
        if (e.Item.Parent != null) //if this item has a parent..
            e.Item.Parent.ChildItems.Remove(e.Item); //use parent to remove child..
        else
            Menu1.Items.Remove(e.Item); //else.. remove from menu itself.
    }
}

Finally, to ensure the user doesn't access pages off-boundary, I added some validation in my master page..

var authorizedRoles = SiteMap.CurrentNode.Roles; //obtain the list of authorized roles for the current page

if (authorizedRoles == null || authorizedRoles.Count == 0) // no roles defined for this node
    isAuthorized = false;
else
{
    if (authorizedRoles.Contains("*")) // this page can be accessed by everyone
        isAuthorized = true;

    if (!isAuthorized)
    {
        foreach (string authorizedRoleName in authorizedRoles)
        {
            if (Roles.IsUserInRole(authorizedRoleName) == true)
            {
                isAuthorized = true;
                break;
            }
        }
    }
}

if (!isAuthorized)
    Response.End(); // unauthorised user; kill the page.

I hope this helps whoever faces the same problem. Please let me know if there are better ways to achieve the same result.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top