9

我正在使用 Asp.Net Web Api。我希望能够根据连接的客户端访问权限过滤掉响应对象上的某些字段。

例子:

class Foo
{
    [AccessFilter("Uberlord")]
    string Wibble { get; set; }

    string Wobble { get; set; }
}

返回数据时,Wibble仅当当前用户上下文可以满足“Uberlord”的值时,才应返回该字段。

我正在探索三种途径,但我没有找到可行的解决方案:

  1. 自定义 WebApi MediaTypeFormatter。
  2. 自定义 json.net IContractResolver。
  3. 用于操作响应对象的控制器的某种 AOP 包装器

我的问题是:

  • 自定义格式化程序感觉不是正确的地方,但可能是唯一的选择。
  • 自定义 json 序列化程序无法访问当前上下文,所以我必须解决这个问题。
  • 使用前两个选项,您需要针对每种响应格式、json、xml、某些自定义格式等进行特定的实现。这意味着如果支持另一种响应类型,则需要自定义格式化程序/序列化程序来防止敏感数据泄漏。
  • AOP 控制器包装器需要大量反射。

另一个好处是使用相同的机制从入站请求对象的字段中删除值。

我错过了一个明显的钩子吗?这是否已通过其他方式解决?

4

2 回答 2

4

它实际上比我最初想象的要简单得多。我没有意识到的是,DelegatingHandler可以用来操纵响应以及Web Api Pipeline中的请求。

ASP.NET Web API 消息的生命周期

委托处理程序


委托处理程序是消息管道中的一个可扩展点,允许您在将请求传递到管道的其余部分之前对其进行按摩。返回途中的响应消息也必须通过委托处理程序,因此任何响应也可以在此扩展点进行监视/过滤/更新。

如果需要,委托处理程序也可以绕过管道的其余部分并自己发回 Http 响应。

例子

这是 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)
                {
                    ((SomeObject)content.Value).SomeProperty = null;
                }

                //Or replace the content
                response.Content = new ObjectContent(typeof(object), new object(), new JsonMediaTypeFormatter());

                return response;
            });
    }
}

有关如何实现委托处理程序并将其添加到管道的 Microsoft 文章。ASP.NET Web API 中的 HTTP 消息处理程序

于 2013-07-04T13:55:50.393 回答
0

我在这里的工作中有一个类似的问题:ASP.NET WebAPI Conditional Serialization based on User Role

我提出的一个建议的解决方案是让我的 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-03T16:03:04.957 回答