13

我从 Asp.Net Web API 开始,这是我的问题:

我实现了一个自定义授权过滤器来检查我的消息头以查找 API 密钥。基于此 API 密钥,我检索了我的用户,然后我想看看他是否可以访问某些资源。我要检查的资源 ID 在 HTTP 请求的参数上。但是当我使用 AuthorizationFilter 方法时,操作参数列表是空的。

我怎样才能做到这一点 ?

如果我使用 ActionFilter 代替授权过滤器,我如何确定这将是第一个执行的过滤器?在全球范围内,如何指定过滤器的执行顺序?

最后一个问题,是否可以在“管道上”添加一些我可以在任何过滤器上检索的数据?类似于会话存储但仅限于请求的东西?

感谢您的任何回复

4

2 回答 2

24

授权属性在参数绑定运行之前运行,因此您不能(如您所见)使用该ActionArguments集合。相反,您需要将请求 uri 用于查询参数,并将路由数据用于 uri 参数,如下所示。

//request at http://localhost/api/foo/id?MyValue=1
public class MyAuthorizationAttribute : AuthorizeAttribute
{
    protected override bool IsAuthorized(HttpActionContext actionContext)
    {
        //will not work as parameter binding has not yet run
        object value;
        actionContext.ActionArguments.TryGetValue("id", out value);

        //Will get you the resource id assuming a default route like /api/foo/{id} 
        var routeData = actionContext.Request.GetRouteData();
        var myId = routeData.Values["id"] as string;

        //uri is still accessible so use this to get query params
        var queryString = HttpUtility.ParseQueryString(actionContext.Request.RequestUri.Query);
        var myQueryParam = queryString["MyValue"];

        //and so on
    }
}

关于执行顺序

有 3 种不同的方法可以使用FilterScope 枚举指定过滤器的执行顺序...范围是 Global、Controller 和 Action。是“全球性的AuthoriseAttribute”,因此它

在 Controller 之前指定一个动作。

如果您需要在这 3 个范围内指定执行顺序,那么您应该在此处阅读这篇博客文章,您需要在其中实现一个FilterProvider

向管道添加一些数据

对请求使用属性集合,此集合在请求期间可用。

    protected override bool IsAuthorized(HttpActionContext actionContext)
    {
        actionContext.Request.Properties.Add("__MYKEY__","MyValue");

        //access this later in the controller or other action filters using
        var value = actionContext.Request.Properties["__MYKEY__"];

    }
于 2013-04-17T08:12:55.770 回答
1

获取参数的另一种方法是Execute绑定参数。

try
{
    var binding = actionContext.ActionDescriptor.ActionBinding;
    var parameters = binding.ParameterBindings.OfType<ModelBinderParameterBinding>();
    var newBinding = new HttpActionBinding(actionContext.ActionDescriptor, parameters.ToArray());
    newBinding.ExecuteBindingAsync(actionContext, new CancellationToken());
    var id = actionContext.ActionArguments["id"] as string;
}
catch
{
    base.HandleUnauthorizedRequest(actionContext);
}

注意:您需要确保仅过滤来自请求 URI 的参数,因为我注意到对预期来自请求正文的任何​​参数执行绑定将不再传递给实际行动。即那些参数将为null

这只是为了说明您可以这样做,我建议您使用GetRouteData()/RouteData它,因为它不太可能破坏 ASP.NET MVC 模型绑定的进一步流程。

var routeData = actionContext.ControllerContext.RouteData;
var id = routeData.Values["id"] as string;
于 2013-10-17T15:49:11.573 回答