基于用户角色的ASP.NET WebAPI条件序列化

11
我有一个ORM(NHibernate),将映射到POCO中,并在ApiController中返回。 我知道JSON.NET可以让我在我的模型上放置条件序列化方法(ShouldSerialize*); 但是,这些模型及其方法对它们的环境一无所知,也不应该知道。 我想根据用户登录网站时的角色,有条件地序列化一个模型或其中一个或多个属性。 我可以理解如何进行概念上的操作,但在某些方面感到困惑。 这是一个示例模型:
public class SomeModel
{
    public string SomeProperty { get; set; }

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

我希望能够在属性上标记一个"敏感"属性。然后,在WebApi对其进行序列化输出时,我希望它检查该属性是否存在此属性,并检查用户的角色。如果用户在指定的角色中,则序列化程序应将该属性序列化,否则将屏蔽或简单地不序列化它。所以,我是否需要编写自己的自定义格式化程序来处理这个问题,还是有一种方法可以连接到内置的格式化程序来执行此检查?或者我的想法过于受限,有其他方法来解决这个问题吗?

我曾考虑过另一种处理方式是在ORM级别上进行,但在网上找不到好的示例。

非常感谢!

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

3个回答

9
如提出的问题所述,我曾提出过问题“基于权限的WebApi端点上下文序列化”,并已经自行回答。 我最初考虑使用MediaFormatter,但我认为这将限制您可以返回哪种类型的响应。 如果您想返回JSON和XML,则需要实现两个格式化程序。 为了只在一个位置实现过滤器,您需要向更高的栈DelegatingHandler

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

在您的情况下,您需要反射对象并挑选出包含您属性的任何字段,并将这些值设置为null。如果返回JSON或XML,则如果值为null,则响应中不包括属性,因此您甚至不会泄露属性名称。
示例
以下是使用反射过滤响应对象内容上实现DelegatingHandler的示例。它假定对象层次结构是平面的,因此如果您有嵌套对象,则需要导航对象图并对层次结构中的每个对象执行相同操作。
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]);
            }
        }   
    }
}

0
我想到的一个解决方案是让我的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
}

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接