ASP.NET WebAPI Условная сериализация на основе роли пользователя

У меня есть ORM (NHibernate), который отображается на POCO, которые будут возвращены в ApiControllers. Я понимаю, что JSON.NET позволяет мне использовать методы условной сериализации (ShouldSerialize*) на моих моделях; однако эти модели и их методы ничего не знают об окружающей среде, равно как и не должны. Я хотел бы условно сериализовать модель или одно или несколько ее свойств в зависимости от роли пользователя, когда они вошли на мой веб-сайт. Я могу концептуально понять, как это можно сделать, но я потерялся в одной части. Вот пример модели:

public class SomeModel
{
    public string SomeProperty { get; set; }

    [Sensitive]
    public string SomeOtherProperty { get; set; }
}

Я хотел бы иметь возможность поместить атрибут в свойство, чтобы пометить его как "Чувствительный". Затем в моем WebApi, когда он сериализует его для вывода, я хотел бы, чтобы он проверил модель для этого атрибута и, если он существует, он должен проверить роль пользователя. Если пользователь находится в указанной роли, то сериализатор должен сериализовать атрибут, иначе он либо замаскирует его, либо просто не сериализует его. Так должен ли я написать свой собственный модуль форматирования, чтобы справиться с этим, или есть способ подключиться к встроенным для выполнения этой проверки? Или я слишком ограничен в своем мышлении, и есть другой способ справиться с этим?

Я действительно думал, что еще один способ справиться с этим - на уровне ORM, но не смог найти хороших примеров в Интернете.

Очень признателен!

РЕДАКТИРОВАТЬ: я нашел еще один подобный вопрос здесь: контекстная сериализация от конечной точки WebApi на основе разрешений, но не было никакого решения. Кроме того, мне не нравится идея настройки ролевого доступа в моделях с помощью атрибутов. Я считаю, что это должно быть обработано в веб-приложении.

3 ответа

Решение

Как упомянуто в вопросе, я поднял вопрос " Контекстная сериализация с конечной точки WebApi на основе разрешений ", на который я ответил сам. Я изначально смотрю на использование MediaFormatter но я верю, что это ограничит вас тем, какой ответ вы могли бы получить. Если вы хотите вернуть JSON и XML, вам нужно реализовать два средства форматирования. Чтобы реализовать фильтр только в одном месте, вам нужно подняться выше по стеку к DelegatingHandler,

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

В вашем senario вам нужно будет отразить объект и выбрать все поля, которые содержат ваш атрибут, и установить для этих значений значение null. Если вы возвращаете JSON или XML, то свойства не включаются в ответ, если значения равны нулю, так что вы даже не пропустите имя свойства.

пример

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

public class ResponseDataFilterHandler : DelegatingHandler
{
    protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        return base.SendAsync(request, cancellationToken)
            .ContinueWith(task =>
            {
                var response = task.Result;

                //Manipulate content here
                var content = response.Content as ObjectContent;
                if (content != null && content.Value != null)
                {
                    FilterFields(content.Value);
                }

                return response;
            });
    }

    private void FilterFields(object objectToFilter)
    {
        var properties = objectToFilter
                             .GetType()
                             .GetProperties(
                                 BindingFlags.IgnoreCase |
                                 BindingFlags.GetProperty |
                                 BindingFlags.Instance |
                                 BindingFlags.Public);

        foreach (var propertyInfo in properties)
        {
            if (propertyInfo.GetCustomAttributes(typeof(SensitiveAttribute), true).Any())
            {
                propertyInfo.SetValue(objectToFilter, null, new object[0]);
            }
        }   
    }
}

Вы можете использовать условную сериализацию, встроенную в Json.Net. Вот статья, описывающая это.

http://blog.mariusschulz.com/2013/04/15/conditionally-serializing-fields-and-properties-with-jsonnet

Возможно, методы 'ShouldSerialize...' могли бы проверить текущего участника, из которого вы можете проверить его роли?

Предлагаемое решение, которое я придумала, состоит в том, чтобы мой ApiController наследовал от BaseApiController, который переопределяет функцию инициализации для установки соответствующего форматера в зависимости от роли пользователя:

protected override void Initialize(System.Web.Http.Controllers.HttpControllerContext controllerContext)
{
    base.Initialize(controllerContext);
    // If the user is in a sensitive-data access role
    controllerContext.Configuration.Formatters.Add(/*My Formatter*/);
    // Otherwise use the default ones added in global app_start that defaults to remove sensitive data
}
Другие вопросы по тегам