ASP.NET web.sitemap - роли, похоже, не контролируют видимость?

У меня есть (простая) карта сайта, и я пытаюсь понять, почему всегда отображается какое-то подменю.

<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
  <siteMapNode url="~/Login.aspx" title="Home" description="RivWorks" roles="*">
    <siteMapNode url="" title="Dashboard" description="" roles="campaigns, auto_negotiation">
      <siteMapNode url="CampaignBuilder.aspx" title="Campaign Manager" description="Manage your campaign settings" roles="campaigns" />
      <siteMapNode url="ProductManager.aspx" title="Negotiation Manager" description="Manage your product and negotiation settings" roles="auto_negotiation" />
    </siteMapNode>
    <siteMapNode url="" title="Support Options" description="" roles="customers, customer_super, riv_admins, riv_super">
      <siteMapNode url="ChangePassword.aspx" title="Change Password" description="" roles="customers, customer_super, riv_admins, riv_super" />
      <siteMapNode url="http://rivworks.zendesk.com/requests/anonymous/new" title="Submit a Support Ticket" description="" roles="customers, customer_super, riv_admins, riv_super" />
      <siteMapNode url="http://rivworks.zendesk.com/forums/49919/entries" title="Tips &amp; Tricks" description="" roles="customers, customer_super, riv_admins, riv_super" />
    </siteMapNode>
  </siteMapNode>
</siteMap>

<ч/" > ПРИМЕЧАНИЕ: WEB.CONFIG SETTINGS

<siteMap defaultProvider="XmlSiteMapProvider" enabled="true">
  <providers>
    <add name="XmlSiteMapProvider"
         description="Default Site Map Provider"
         type="System.Web.XmlSiteMapProvider"
         siteMapFile="Web.sitemap"
         securityTrimmingEnabled="true" />
  </providers>
</siteMap>

<ч/" > У меня есть опция главного меню "Dashboard". В этом пункте меню есть 2 варианта: 1) менеджер кампании и 2) диспетчер переговоров. Теперь интересно, когда я нахожусь в роли роли ИЛИ роли автосогласования, я вижу элементы подменю Dashboard и BOTH. Это не то поведение, которое я ожидал. Я ожидаю увидеть только оба подменю, когда я нахожусь в роли роли И роли в рекламных кампаниях. Сценарий OR должен предоставить мне элемент меню панели инструментов и один ИЛИ другой подпункт...

Я делаю что-то неправильно здесь или думаю неправильно?

ТИА

Ответ 1

Я подозреваю, что вы попали в ловушку, которую все мы делаем, полагая, что атрибут role ограничивает видимость узлов. Это не так, это на самом деле расширяет видимость. Все ограничения сделаны с помощью стандартного раздела в web.config.

Полный текст ниже взят из оригинального сообщения на https://web.archive.org/web/20130408064047/http://ipona.com/asp-net-site-maps-security-trimming-and-roles/)

Это один из наиболее часто задаваемых вопросов, и он кажется постоянным источником путаницы для всех, как и для меня, когда я впервые прочитал об этом. ASP.NET SiteMap позволяет определять навигационную структуру как набор элементов XML, которые идеально подходят для описания иерархии пунктов меню. Эти элементы XML являются элементом siteMapNode, который имеет роли атрибутов. Кажется очевидным, что это определяет роли, которые может видеть этот элемент, но очевидное на самом деле неправильно. Вот самый важный факт о картах сайта:

Атрибут role не ограничивает видимость узла.

Это должно быть достаточно ясно, даже если это все еще кажется неправильным. Вот как это работает. Все ограничения на страницы обрабатываются через авторизацию. Это можно сделать либо в основном файле web.config, либо в файлах web.config в папках. Например, предположим, что есть папка администратора, в которой хранятся все страницы администрирования. Вы только хотите, чтобы эти страницы были доступны пользователям в роли администратора. Вы бы настроили свою авторизацию так:

<location path="Admin">
  <system.web>
    <authorization>
      <allow roles="Admin" />
      <deny users="*" />
    </authorization>
  </system.web>
</location>

Папка администратора теперь не может быть доступна любому, кто не находится в роли администратора; если вы не в роли администратора и пытаетесь перейти на страницу в папке администратора, либо по ссылке на другой странице, либо введя URL-адрес непосредственно в браузере, вы будете перенаправлены на страницу входа. Вы можете иметь несколько элементов location в вашем файле web.config для разных папок или даже для отдельных файлов; на самом деле, если у вас есть ограниченный сайт, вы можете явно открыть определенные страницы, такие как страница входа; Трудно войти на сайт, если у вас нет авторизации для доступа к странице входа. Если вы предпочитаете не загромождать базовый файл web.config, вы можете создать файл web.config в папке Admin с теми же правилами; вам не нужен элемент location, так как конфигурация применяется к текущей папке.

Так что авторизация сделана; доступ к страницам заблокирован. Теперь давайте рассмотрим навигацию. Инфраструктура навигации ASP.NET учитывает авторизацию, но только если вы настраиваете ограничение безопасности на провайдере, который не настроен по умолчанию. Это означает, что вам нужно добавить конфигурацию карты сайта в web.config:

<siteMap enabled="true" defaultProvider="AspXmlSiteMapProvider">
  <providers>
    <clear />
    <add name="AspXmlSiteMapProvider" securityTrimmingEnabled="true"
     type="System.Web.XmlSiteMapProvider, System.Web, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
     siteMapFile="web.sitemap"/>
  </providers>
</siteMap>

Большая часть этого настраивается на уровне компьютера, когда установлен ASP.NET, но по умолчанию значение securityTrimmingEnabled имеет значение false. То, что делает выше, очищает существующую конфигурацию и добавляет новую запись с атрибутом, установленным в true. На этом этапе навигационная структура теперь будет соблюдать правила авторизации, поэтому пункты меню не будут отображаться, если у пользователя нет авторизации для этого элемента; Неважно, используете ли вы Menu или TreeView для отображения пунктов меню, критически важной частью является использование SiteMapDataSource (или API Sitemap, если вы создаете меню вручную). Если у вас есть пользовательский поставщик карты сайта, например, управляемый базой данных (например, этот в MSDN), то для этого может потребоваться выполнить собственную проверку безопасности, но это зависит от того, от какого базового класса вы наследуете. Это еще одна история для другого поста, хотя.

Так что, если вам не нужно изменять сами элементы карты сайта, для чего нужен атрибут role? Что ж, это работает противоположным образом, который вы, вероятно, ожидаете, открывая видимость узла, показывая узел, если у пользователя есть заявленная роль, даже если у него нет авторизации для доступа к самой странице (потому что правило авторизации ограничивает их доступ Это). Зачем ты это делаешь? Ну, вы должны понять, как работает подстройка безопасности. При принятии решения, может ли пользователь видеть узел, проверяются права доступа и права доступа к физическому файлу; если какой-либо сбой, то узел считается недоступным. Существует два очень распространенных случая, когда проверка файлов не выполняется:

  1. URL не является локальным. Если файл не существует локально, то никакой проверки не может быть.
  2. Там нет URL. Узел может быть просто контейнерным узлом с дочерними страницами, но без самой страницы.

В обоих этих случаях проверка физического файла не удалась, поэтому узел не будет показан. Поэтому вам может потребоваться открыть видимость узла. Например, рассмотрим следующее:

<siteMapNode title="Admin" roles="Admin">
    <siteMapNode url="~/Admin/membership_CreateMember.aspx" title="Create User" />
    <siteMapNode url="~/Admin/membership_GetUsers.aspx" title="View Users" />
    <siteMapNode url="~/Admin/roleManager_CreateRole.aspx" title="Create Role" />
    <siteMapNode url="~/Admin/roleManager_AddUserToRole.aspx" title="Add User to Role" />
</siteMapNode>

Здесь узел администратора не имеет физической страницы, он просто позволяет организовать элементы администрирования в их собственном подменю. Без атрибута дополнительных ролей узел и дочерние элементы не будут отображаться, но role = "Admin" указывает, что узел также должен быть показан пользователям в роли Admin, даже если проверка безопасности не удалась. Нам не нужен атрибут на дочерних узлах, потому что у них есть физические страницы, поэтому проверка файлов будет успешной.

Так что это довольно просто, если вы помните правила:

  • Настройте ограничения безопасности на страницах с авторизацией в web.config.
  • Переопределите провайдера карты сайта, включив настройку безопасности.
  • Добавьте атрибут ролей в узлы карты сайта, чтобы расширить видимость.

Ответ 2

Вы хотите, чтобы ASP.NET называл "" Обрезка безопасности сайта". Вы уже выполнили большую часть работы, а именно, назначив роли узлам в файле Sitemap. Теперь все, что вам осталось сделать, немного конфигурировано.

В web.config добавьте нового поставщика карты сайта, используя стандартный XmlSiteMapProvider, но с securityTrimmingEnabled="true" и сделайте это поставщиком по умолчанию:

<system.web>
  <siteMap defaultProvider="XmlSiteMapProvider" enabled="true">
    <providers>
      <add name="TrimmedSitemap"
        type="System.Web.XmlSiteMapProvider"
        siteMapFile="Web.sitemap"
        securityTrimmingEnabled="true" />
    </providers>
  </siteMap>
</system.web>

Ответ 3

Я знаю, что это очень старый, но я унаследовал некоторый старый код и столкнулся с той же проблемой. Мой начальник хотел, чтобы я временно скрыл видимость функций из одной роли, но все же сделал ее доступной в другом месте на сайте. Я полностью ожидал просто удалить роль из карты сайта, и она не будет видна этой роли. Эрик четко объяснил, как он намеревался улучшить видимость, а не ограничить.

Я просто хотел привести пример того, как заставить его функционировать так, как вы (и я) ожидали, что он будет функционировать (роль должна присутствовать в обоих местах).

<asp:Menu ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1" OnMenuItemDataBound="Menu1_TreeNodeDataBound" />

protected void Menu1_TreeNodeDataBound(object sender, MenuEventArgs e)
{
    if (e.Item.DataItem!=null && ((SiteMapNode)e.Item.DataItem).Roles.Count > 0 && HttpContext.Current.User.Identity.IsAuthenticated)
    {
        string role = Common.GetUserRole();  // I have a single role provider and a common function to get the role.  You could always loop through Roles and use HttpContext.Current.User.IsInRole()         
        if (role.Length > 0)
        {
            if (!((SiteMapNode)e.Item.DataItem).Roles.Contains(role))
            {
                if (e.Item.Parent != null)
                    e.Item.Parent.ChildItems.Remove(e.Item);
                else
                    Menu1.Items.Remove(e.Item);
            }
        }            
    }
}