Запрет редактирования свойств модели в ASP.NET MVC

в 11:36, , рубрики: .net, asp.net mvc, Песочница, метки: ,

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

Задача

Допустим, что у нас есть модель клиента, содержащая его идентификатор, имя и ИНН.

public class ClientViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Inn { get; set; }
}

Данные поступают на страницу в виде модели. Совершив необходимые действия, пользователь отправляет HTTP-запрос, который содержит в качестве параметров значения полей формы. Перед тем, как будет вызван Action-метод, отвечающий за обработку запроса, DefaultModelBinder связывает полученные из формы параметры с моделью данных. Все изменения, внесенные пользователем, отображаются в свойствах полученной модели.
Запрет редактирования свойств модели в ASP.NET MVC
Но что, если некоторые свойства необходимо защитить от изменения, чтобы пользователь, не имеющий на это прав, случайно или со злым умыслом, не смог нарушить целостность данных?! Для решения данной проблемы необходимо разработать механизм, который позволил бы запрещать изменение некоторых свойств модели конкретным ролям пользователей.

Идея решения

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

Решение

Создание атрибута. В строке Roles через запятую будут указываться запрещенные роли:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class DenyWriteRolesAttribute : Attribute
{
    public string Roles { get; set; }
}

Новый механизм привязки моделей реализуется наследованием от стандартного класса DefaultModelBinder. Необходимо переопределить метод BindProperty, отвечающий за привязку конкретных свойств. Если у свойства есть атрибут DenyWriteRoles, и хотя бы одна роль пользователя совпадает с любой из ролей, указанных в атрибуте, то привязка не происходит:

public class CustomModelBinder : DefaultModelBinder
{
    protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor)
    {
        var a = propertyDescriptor.Attributes.OfType<DenyWriteRolesAttribute>().FirstOrDefault();

        if (a != null && a.Roles.Split(',').Any(r => controllerContext.HttpContext.User.IsInRole(r)))
            return;
            
        base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
    }
}

Ниже приведен пример установки CustomModelBinder в качестве привязчика моделей по умолчанию в файле Global.asax.cs:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    ModelBinders.Binders.DefaultBinder = new CustomModelBinder();

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
}

Теперь, чтобы запретить пользователям с ролью “user” изменять свойство модели “Name”, достаточно установить атрибут DenyWriteRoles:

public class ClientViewModel
{
    public int Id { get; set; }
    [DenyWriteRoles(Roles = "user")]
    public string Name { get; set; }
    public string Inn { get; set; }
}

Результат

Пользователь, при работе с приложением, имеет возможность видеть все свойства модели, однако, изменения, касающиеся защищенных свойств, остаются проигнорированными.
Запрет редактирования свойств модели в ASP.NET MVC

Автор: Andrew_m75

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js