ASP.NET MVC: авторизация внутри действия - предлагаемые шаблоны или это запах? - PullRequest
10 голосов
/ 20 мая 2009

У меня есть приложение ASP.NET MVC, использующее атрибуты авторизации на контроллерах и действиях. Это работало хорошо, но появилась новая морщина.

Объект: Отгрузка

Роли: Доставка, Бухгалтерия, Обычный пользователь

Отгрузка проходит через рабочий процесс. В состоянии A это может быть отредактировано только отправкой В состоянии B это может быть отредактировано только бухгалтерией.

У меня есть ShipmentController и действие по редактированию. Я могу поставить атрибут Authorization, чтобы ограничить действие Edit только этими двумя ролями, но это не различает, в каком состоянии находится Отгрузка. Мне нужно выполнить некоторую Авторизацию внутри действия перед вызовом службы, чтобы определить, является ли пользователь действительно авторизован для выполнения действия редактирования.

Итак, у меня осталось два вопроса:

1) Какой хороший способ получить авторизацию в действии. Действие контроллера вызывает службу, а затем служба выполняет соответствующие вызовы к объекту отгрузки (количество обновлений, дата обновления и т. Д.). Я точно знаю, что хочу, чтобы объект «Отгрузка» не зависел от требований авторизации. С другой стороны, я не совсем понимаю, хочу ли я, чтобы служебный объект знал об авторизации или нет. Есть ли хорошие шаблоны для этого?

2) Является ли моя проблема симптомом плохого дизайна? Вместо ShipmentController я должен иметь StateAShipmentController и StateBShipmentController? У меня нет какого-либо полиморфизма, встроенного в объект Shipment (состояние - просто перечисление), но, возможно, мне следует, а может быть, контроллеры должны это отражать.

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

Спасибо!

Ответы [ 4 ]

3 голосов
/ 21 мая 2009

Я не вижу проблемы с методом Action, выполняющим дальнейшие проверки авторизации внутри него. Вы можете использовать поставщика ролей для получения детальной авторизации, которую вы ищете. Пожалуйста, извините мой синтаксис здесь - он, вероятно, груб, и я не проверял это.

[Authorize(Roles="Shipping, Accounting")]
public ActionResult Edit(int id)
{
    Shipment shipment = repos.GetShipment(id);


    switch (shipment.State)
    {
         case ShipmentState.A:
         if (Roles.IsUserInRole("Shipping"))
                return View(shipment);
         else
                return View("NotAuthorized");
         break;
         case ShipmentState.B:
         if (Roles.IsUserInRole("Accounting"))
                return View(shipment);
         else
               return View("NotAuthorized");
         break;
         default:
              return View("NotAuthorized");
     }
}
2 голосов
/ 20 мая 2009

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

Для числа 1 существует ряд шаблонов, которые обеспечивают расширенное поведение в объектах домена. При двойной диспетчеризации вы передаете ссылку на абстракцию службы (интерфейс) методу объекта. Тогда он может сделать свое дело. Вы также можете написать сервисную заявку, которая принимает Отгрузку и выполняет всю работу.

На номер 2 не обязательно. Возможно, вам придется абстрагировать концепцию «контекстной отправки» в службу, которая выяснит, в каком контексте отправки вы находитесь. Но я бы сказал, что это вам понадобится снова.

1 голос
/ 22 мая 2009

В дополнение к ответу, приведенному выше, вы можете вернуть HttpUnauthorizedResult вместо создания собственного представления для NotAuthorized. Это перенаправит на страницу входа и будет вести себя как обычный атрибут [Authorize]

1 голос
/ 20 мая 2009

Вы можете взглянуть на Rhino.Security , его можно использовать для реализации авторизации пользователей в подобных сценариях.

...