Pergunta

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.

Foi útil?

Solução

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top