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

в 19:14, , рубрики: .net, ASP, asp.net mvc, метки: ,

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

Задача

Предположим, что есть класс ClientViewModel.

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

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

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

Но что, если значение поля Inn нельзя показывать некоторым ролям пользователей? Необходимо разработать механизм, который позволял бы декларативно указывать роли, для которых запрещено чтение некоторых свойств.

Идея решения

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

Решение

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

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

    public void OnMetadataCreated(ModelMetadata metadata)
    {
        if (Roles.Split(',').Any(IsUserInRole))
            metadata.Model = metadata.SimpleDisplayText = "Чтение запрещено";
    }

    private bool IsUserInRole(string roleName)
    {
        return HttpContext.Current != null &&
                    HttpContext.Current.User != null &&
                    HttpContext.Current.User.IsInRole(roleName);
    }
}

Атрибут должен реализовать интерфейс IMetadataAware, чтобы иметь возможность изменять метаданные модели. В единственном методе интерфейса OnMetadataCreated определяется, относится ли хоть одна из ролей пользователя к списку запрещенных. Если таковая есть, то значение свойства, и его строковое представление заменяются текстом «Чтение запрещено».
Дополнительно необходимо запретить передачу защищенных свойств в модель из Web формы в момент привязки, чтобы текст сообщения или внесенные пользователем изменения не попали обратно в модель. Для этого подойдет пример, рассмотренный мной в статье «Запрет редактирования свойств модели в ASP.NET MVC». Необходимо немного изменить метод BindProperty в классе CustomModelBinder следующим образом:

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

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

И установить его в качестве привязчика по умолчанию Global.asax.cs:

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

    ModelBinders.Binders.DefaultBinder = new CustomModelBinder();

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

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

public class ClientViewModel
{
    [DisplayName("Индекс")]
    public int Id { get; set; }

    [DisplayName("Название")]
    public string Name { get; set; }

    [DisplayName("ИНН")]
    [DenyReadRoles(Roles = "User")]
    public string Inn { get; set; }
}

Результат

Теперь, при работе с данными, пользователь, которому запрещено чтение свойства Inn, в соответствующих полях представления, будь то страница для чтения или Web форма для редактирования, будет видеть текст «Чтение запрещено». Изменения, внесенные им в форме для редактирования, так же останутся проигнорированными.

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

Автор: Andrew_m75

Источник


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


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