Защита контроллеров / действий ASP.NET MVC3 - PullRequest
1 голос
/ 05 июля 2011

Я разрабатываю приложение MVC 3, в котором несколько арендаторов находятся в одной базе данных.

Каков наилучший способ запретить пользователям редактировать / просматривать данные других арендаторов в MVC? (то есть кто-то может напечатать '/ People / Edit / 1' и отредактировать человека с Id 1 - независимо от того, являются ли они частью данных об арендаторах или нет).

Я знаю, что могу переопределить «OnActionExecuting (ActionExecutingContext filterContext)» для каждого контроллера, но звучит странно, что приходится обрабатывать каждое действие отдельно, получать ID или OBJECT в зависимости от того, является ли это POST или GET, а затем проверять, выполняет ли операция разрешено.

Есть идеи получше?

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

Заранее спасибо.

Ответы [ 3 ]

1 голос
/ 05 июля 2011

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

public class Person
{
    public string Id { get; set; }
    ... some other properties
}

Теперь вместо:

[HttpPost]
public ActionResult Edit(string id)
{
    ...
}

напишите:

[HttpPost]
public ActionResult Edit(Person person)
{
    ...
}

и затем напишитепользовательская модель привязки для персоны:

public class PersonModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var id = bindingContext.ValueProvider.GetValue("id");
        // check if an id was provided and if the user is authenticated
        if (!controllerContext.HttpContext.User.Identity.IsAuthenticated || id == null)
        {
            throw new HttpException(403, "Forbidden");
        }
        var currentUser = controllerContext.HttpContext.User.Identity.Name;
        // fetch the person from your repository given the id and belonging 
        // to the currently authenticated user
        var person = _repository.GetPerson(id.AttemptedValue, currentUser);
        if (person == null)
        {
            // no person found matching
            throw new HttpException(403, "Forbidden");
        }
        return person;
    }
}

, которую вы зарегистрируете в Application_Start:

ModelBinders.Binders.Add(typeof(Person), new PersonModelBinder());
0 голосов
/ 05 июля 2011

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

0 голосов
/ 05 июля 2011

Оригинальный ответ

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

Одна из вещей, которую вы можете сделать, - это назначить свой собственный атрибут авторизации http://msdn.microsoft.com/en-us/library/system.web.mvc.authorizeattribute.aspx Или вы можете создать глобальный фильтр действий. http://www.asp.net/mvc/tutorials/understanding-action-filters-cs

Дополнительная информация о том, как вы могли бы сделать это на основе запроса в комментарии

public class MySuperFilter : ActionFilterAttribute
    {
        //Called by the MVC framework before the action method executes.
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            String user = filterContext.HttpContext.User.Identity.Name;
            int id = int.Parse(filterContext.RouteData.GetRequiredString("Id"));
            if (!IsValidUser(user,id))
            {
                filterContext.Result = new RedirectToRouteResult(
                        new RouteValueDictionary {{ "Controller", "YourController" },
                                      { "Action", "YourAction" } });


            }

            base.OnActionExecuting(filterContext);
        }

        private bool IsValidUser(string user,int id)
        {
            //Check if the user has acces to the page
            return true;
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...