Уменьшите дублирующийся код в действиях контроллера - PullRequest
0 голосов
/ 09 ноября 2009

Чтобы пользователи и администраторы сайта могли просматривать / добавлять / редактировать / удалять данные в моем приложении, я выбрал этот маршрут:

routes.MapRoute("ClientRoute",
       "{account}/{controller}/{action}/{id}",
       new { controller = "Home", action = "Index", id = "" });

, что приводит к таким маршрутам, как: mvcapp.net/1234/contact/add.

Чтобы пользователи {кроме администраторов} не имели доступа к данным других клиентов, я добавил следующий код в действия моего контроллера.

...
   var model = repos.GetSomeData();
   if (User.IsInRole("Admin") == false) {
    if (account == Profile["Client"])
       return View(model);
    else
       return View("WrongClient");
    }
...

Каков наилучший способ сделать это?

РЕШЕНИЕ, КОТОРОЕ Я ПОШЕЛ С

public class BaseController : Controller {
  protected override OnActionExecuting(ActionExecutingContect filterContext) {
      if (filterContext.RouteData.Values["account"] != null) {
         string client = filterContext.RouteData.Values["account"].ToString();
         if (User.IsInRole("admin") == false) {
            if (Profile.Clients.Contains(account) == false)
              filterContext.Result = new ViewResult() {ViewName = "WrongClient"};
          }
      }
  }
}

Ответы [ 4 ]

1 голос
/ 09 ноября 2009

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

Если вас беспокоит передача пользовательской информации в метод репозитория (как Jabe обсуждает в своем комментарии ниже), тогда вы можете вернуть IQueryable из репозитория и выполнить запрос Linq для этого, чтобы выполнить подстройку безопасности.

0 голосов
/ 09 ноября 2009

Я не уверен, что делает Profile ["AccountNumber"] (или откуда появился Profile), но предполагается, что вы можете создать этот объект в любое время (или, если он уже создан);

Вы можете сделать следующее (поместить это в свой контроллер):

protected override void ExecuteCore()
{
    var model = repos.GetSomeData(int.Parse(base.RouteData.Values["client"])));
    if (User.IsInRole("Admin") == false && Profile["AccountNumber"].ToString() != model.AccountNumber)
    {
          ViewData["Error"] = "You can't access this page";
          View("WrongClient").ExecuteResult(ControllerContext);
    }
    else
          base.ExecuteCore();

}

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

Идея взята из: http://forums.asp.net/t/1382514.aspx

0 голосов
/ 09 ноября 2009

Действительно ли необходимо, чтобы клиент был частью маршрута, учитывая, что у вас уже есть эта информация в вашем распоряжении из профиля?

Что касается обработки на уровне хранилища (как упомянуто выше), это может быть немного сложнее, так как может препятствовать доступу к данным, необходимым внутри какого-либо бизнес-процесса, а также не позволять пользователю получать к нему доступ. Конечно, вы можете создать отдельные отфильтрованные / нефильтрованные методы для обработки этого. Кроме того, это может быть способом избежать смешивания клиентских данных, когда-либо допустимого.

Большую часть времени в нашем приложении добавляется / вставляется / удаляется только элемент верхнего уровня, доступ к которому каким-то образом должен быть ограничен. Это также ограниченный набор данных, который необходимо ограничить таким образом, поэтому я обычно пишу код, который выдает исключение какого-либо вида прямо в контроллер в случае нарушения правил доступа для этого элемента.

Если правила для вашего приложения очень похожи, вы можете избежать повторения кода несколькими способами. На ум приходят пользовательский базовый класс ActionFilter или пользовательский контроллер. Если у каждой строки в вашей базе данных есть идентификатор клиента или какая-то такая схема, другой вариант будет иметь каждый объект вашего домена, реализующий интерфейс, предоставляющий этот идентификатор. Затем вы можете написать повторно используемый код (методы расширения в стиле mixin и т. Д.), Который использует этот интерфейс в качестве основы для применения различных правил безопасности.

0 голосов
/ 09 ноября 2009

Для этого конкретного примера у Азама Шарпа есть возможное решение в его блоге . Я буквально наткнулся на эту статью не более пяти минут назад. Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...