Скрытие Html.ActionLinks на основе безопасности на основе ролей - PullRequest
6 голосов
/ 05 мая 2011

Я использую @RenderSection("Contextual", false) в своем _Layout.cshtml, чтобы позволить различным представлениям отображать там свой конкретный контент.У некоторых их нет, у других они есть.

Кроме того, я использую безопасность на основе ролей и ActionFilter, чтобы контролировать, имеет ли конкретный пользователь доступ к определенным действиям контроллера и, следовательно, маршруты на моем сайте.

Что я хотел бы сделать, так это предоставить секцию @RenderSection("Contextual", false) в моем _Layout.cshtml, а затем попросить конкретную страницу предоставить любой контекстный материал, который имеет смысл для этой страницы , а иметь соответствующий контроллер для обработки проверкио том, может ли пользователь выполнить действие и, возможно, даже увидеть, что параметры существуют , но я не уверен, что правильно об этом думаю.Вот как это происходит в настоящее время:

Сейчас у меня есть раздел в одном из моих файлов Index.cshtml, например:

@section Contextual {
  <div>@Html.ActionLink("Create New", "Create")</div>
  <div>@Html.ActionLink("Generate Report", "Report")</div>
  <div>@Html.ActionLink("Other Stuff", "Other")</div>
}

, а затем в моем соответствующем контроллере, яполучил что-то вроде этого:

[Authorize(Roles = "Editor")]
public ActionResult Create()
{
   // stuff
}

Это будет работать так, как я хочу (нередакторы не смогут создавать новые элементы), но запись Создать доступна для всеобщего обозрения.Я могу сделать что-то вроде этого:

@section Contextual {
  @if (User.IsInRole("Editor"))
  {
     <div>@Html.ActionLink("Create New", "Create")</div>
  }
  <div>@Html.ActionLink("Generate Report", "Report")</div>
  <div>@Html.ActionLink("Other Stuff", "Other")</div>
}

И это работает достаточно хорошо, скрывая ссылку «Создать» от нередакторов, но я нахожусь на грани того, хорошо ли это обрабатывать или нетКроме того, я могу видеть, что в будущем у меня возникает ситуация, когда меняются правила, а затем у меня есть два местоположения для синхронизации: атрибут действия контроллера и код в представлении.

Это разумный подход?Есть ли лучший способ приблизиться к этому?

Ответы [ 2 ]

8 голосов
/ 06 мая 2011

Мне нравится использовать флаги, которые являются более явными для модели представления, которая заполнена на контроллере.

Например:

 // on the controller
 viewModel.CanCrete = User.IsInRole("Editor");
 // ...snip...
 return View(viewModel);
}

Итак, вам необходимо добавить этот флаг в модель представления или, возможно, в базовый класс моделей представления. Вы можете пойти по пути создания Custom Action Filter , чтобы заполнить его несколькими контроллерами или выполнить некоторую обработку в базовом классе контроллера.

Я также хотел бы определить удобный метод расширения:

public static string If( this string s, bool condition )
{
  return condition ? s : String.Empty;
}

В зависимости от того, какие API вы используете, вам также может потребоваться расширить MvcHtmlString.

Тогда в представлении:

@section Contextual {
  <div>@Html.ActionLink("Create New", "Create").If(Model.CanCrete)</div>
  <div>@Html.ActionLink("Generate Report", "Report")</div>
  <div>@Html.ActionLink("Other Stuff", "Other")</div>
}

Вы можете решить, что бы вы хотели сделать с div, вы можете захотеть иметь другого помощника, который оборачивает ссылки в div, или, возможно, вы можете использовать CSS для достижения любого визуального макета, к которому вы стремитесь.

0 голосов
/ 23 мая 2012

Мне очень нравится ответ @ TJB, и я думаю, что на самом деле сделаю что-то похожее.Но если вы хотите пойти другим путем ... вы можете создать свои собственные LinkExtensions, которые перегружают стандартные LinkExtensions.

public static class MyLinkExtensions
{
    public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, YourAccessStuff access)
    {
        if(access.Has(actionName))
        {
            ActionLink(htmlHelper, linkText, actionName);            
        }
        else
        {
            // Maybe only show the link text as if it's disabled and not a link?
            // Maybe do nothing?          
        }
    }
}

Предположим, что «YourAccessStuff» фактически реализован.Это позволило бы централизовать эти проверки доступа, а не прикреплять их к каждой ссылке ActionLink.Недостатком, очевидно, является то, что вы все равно можете забыть поставить проверку безопасности.Использование какого-либо внедрения зависимости также сделало бы это лучше.

...