10

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

объект: Пересылка

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

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

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

Так я остался с двумя вопросами:

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

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

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

Спасибо!

+0

Почему бы не создать свой собственный фильтр [Authorize], подобный фильтру для связанных вещей? –

+0

создание собственного фильтра [Authorize] было бы действительно очень плохой идеей, и именно команда разработчиков ASP.NET MVC действительно действительно сильно обескуражила –

+0

@Josh; Я не согласен. Это не «действительно, очень плохая идея», это только тот, к которому следует относиться с должной осторожностью. Я не видел публичных статей об обескураживании, а тем более с несколькими «действительно и сильно». Единственное реальное «получение» от моего знания - это то, что вы хотите унаследовать атрибут Authorize, предоставленный инфраструктурой, потому что таким образом вы можете гарантировать, что он надежно уволен в нужном месте. – Paul

ответ

2

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

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

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

1

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

3

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

[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"); 
    } 
} 
+0

Хотя это «простое» решение, оно немного пахнет. Hardcoding авторизация на контроллере нарушает SRP и, по крайней мере, должна быть реорганизована в свой класс. –

+0

Этот пример почти кричит для реализации государственного шаблона. – Paul

+1

хе-хе, да, конечно! Как бы это ни было, я хотел убедиться, что я обратился к вопросу ОП, а не увяз в деталях. –

1

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

Смежные вопросы