10

我有一个映射到将在 ApiControllers 中返回的 POCO 的 ORM(NHibernate)。我意识到 JSON.NET 允许我将条件序列化方法 (ShouldSerialize*) 放在我的模型上;然而,这些模型和他们的方法对他们的环境一无所知,也不应该。我想做的是根据用户登录我的网站时的角色有条件地序列化模型或其一个或多个属性。我可以从概念上理解如何做到这一点,但我迷失了一部分。这是一个示例模型:

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

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

我希望能够在属性上放置一个属性以将其标记为“敏感”。然后在我的 WebApi 中,当它序列化它以进行输出时,我希望它检查这个属性的模型,如果它存在,它应该检查用户的角色。如果用户处于指定角色,则序列化程序应序列化该属性,否则它将屏蔽它或根本不序列化它。那么我是否必须编写自己的自定义格式化程序来处理这个问题,或者有没有办法连接到内置的格式化程序来执行这个检查?还是我的思维太局限了,还有另一种处理方式?

我确实认为可以处理的另一种方法是在 ORM 级别,但在网上找不到好的例子。

非常感激!

编辑:我确实在这里找到了另一个类似的问题: 基于权限的 WebApi 端点的上下文序列化, 但没有解决方案。另外,我不喜欢通过属性在模型中设置基于角色的访问的想法。我认为应该在 Web 应用程序中处理。

4

3 回答 3

8

正如问题中提到的,我提出了“基于权限从 WebApi 端点进行上下文序列化”的问题,我自己回答了这个问题。我最初确实考虑过使用 aMediaFormatter但我相信这会限制你返回什么样的响应。如果要返回 JSON 和 XML,则需要实现两个格式化程序。只需要在一个地方实现过滤器,你需要在堆栈的更高层到达DelegatingHandler.

在我的实现中,我想查找客户端可以访问哪些字段,并从响应中删除客户端不应该看到的任何字段。这与您想要做的非常相似。

在您的场景中,您需要反映对象并挑选出包含您的属性的任何字段并将这些值设置为空。如果返回 JSON 或 XML,则如果值为 null,则属性不包含在响应中,因此您甚至不会泄漏属性名称。

例子

下面是一个示例实现,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]);
            }
        }   
    }
}
于 2013-07-05T09:27:58.300 回答
0

您可以使用 Json.Net 中内置的条件序列化。这是一篇描述它的文章。

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

也许“ShouldSerialize...”方法可以检查当前主体,您可以从中检查其角色?

于 2013-11-25T12:20:07.410 回答
0

我提出的一个建议的解决方案是让我的 ApiController 从 BaseApiController 继承,它覆盖 initalize 函数以根据用户的角色设置适当的格式化程序:

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
}
于 2013-07-03T15:57:22.817 回答