在自定义的AuthorizeAttribute中访问QueryString

16

我正在使用Web API,并设置了一个简单的身份验证和授权机制,调用方在查询字符串中传递我发给他们的令牌。因此,他们提交请求的方式如下:

https://mysite.com/api/Ping?token=[issued-token]

我有一个像这样的ApiAuthorizeAttribute:

public class ApiAuthorizeAttribute : System.Web.Http.AuthorizeAttribute
{
    public ApiPermission Permission { get; set; }

    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        switch (Permission)
        {
            case ApiPermission.None: 
               return;

           case ApiPermission.Write:
           case ApiPermission.Read:

               string query = actionContext.Request.RequestUri.Query;
               var nvc = System.Web.HttpUtility.ParseQueryString(query);
               string token = nvc["token"];

               // (my code to map the token to an Authorization for the request)               
               ApiAuthorization auth = ApiToken.GetAuthorization(token);
               if (auth != null && auth.HasPermission(Permission))
                   return;

               HandleUnauthorizedRequest(actionContext);
               return;

           default:
               throw new ArgumentException("Unexpected Permission");
        }
    }
}

那么我可以像这样装饰我的API。注意:这只是一个例子,实际调用将从用户的帐户中读取数据(账户标识符已加密在其令牌中),并返回它。

/// <summary>
/// Ping service that requires a Token with Read permission
/// Returns "Success!"
/// </summary>
[ApiAuthorize(Permission = ApiPermission.Read)]
[HttpGet]
public string Ping()
{
    return "Success!";
}

如您所见,我无法从HttpActionContext参数中的任何地方访问QueryString,只能自己构建它。似乎他们明确从此请求对象中删除了QueryString。我不想在每个API方法中都添加“token”以便将其放入路由数据中。

那么我的问题是:

  1. QueryString是否存在于某处且我只是错过了它?如果没有,有任何想法为什么Microsoft不会将其与此请求对象一起包含? (例如,可能这是一件坏事?)
  2. 是否有更好的方法处理在AuthorizeAttribute中获取令牌(再次不添加到每个调用中)?

顺便说一下,我意识到还有其他(可能更好的)授权选项,例如基本身份验证和OAuth,我不想在这里讨论这个主题。


你尝试过 actionContext.Request.QueryString 吗?https://dev59.com/GnE95IYBdhLWcg3wp_kg - Satpal
@Satpal,是的,当我开始编写代码时,我已经假定该属性存在。但是,那个特定的请求对象没有那个属性。这就是我的问题的关键 - 为什么没有呢? - ThisGuy
actionContext.Request.RequestUri.Query 也可能很有用。https://dev59.com/B2cs5IYBdhLWcg3wfD9P... - Kristopher
3个回答

36

虽然Adam Tal的答案完全有效,在Web API的新世界秩序中,您真的不想使用System.Web命名空间中的任何内容;事实上,您甚至不想引用它。但是,您可以通过GetQueryNameValuePairs()扩展方法访问查询字符串。这将让您放弃System.Web锚定,并仍然获取所需信息。

using System.Net.Http;

var queryString = actionContext.Request
        .GetQueryNameValuePairs()
        .ToDictionary(x => x.Key, x => x.Value);

7
补充一下(因为我找了一会儿才找到),您可以使用 System.Net.Http 命名空间来查找此扩展方法。 - Matt Burland
3
完全正确。特别是如果有人想使用vnext并且摆脱System.Web,你得到了我的赞同。 :) - Adam Tal

12

尝试

using System.Web;

HttpContext.Current.Request.QueryString

有什么想法可以访问POST请求? - PUG
1
@jaminator - 尝试使用HttpContext.Current.Request.Form字典来获取POST数据,而不是从URL中获取数据的QueryString。 - Adam Tal
@AdamTal 数据以JSON POST请求的形式传递给我。 - PUG
@jaminator - 你试过我建议的吗? - Adam Tal
@AdamTal 是的,我做了,因为没有表单将数据从客户端发送到服务器,而是一个json ajax调用,所以Request.Form ["somekey"]为空。 - PUG
显示剩余2条评论

1
NameValueCollection queryString = actionContext.Request.RequestUri.ParseQueryString();

对我有效。


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