Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing QueryString in a custom AuthorizeAttribute

I am using Web API and have setup a simple authentication and authorization mechanism where the caller passes a token that I have issued to them in the query string. So they submit a request like:

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

I have an ApiAuthorizeAttribute like this:

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");
        }
    }
}

Then I can decorate my APIs like this. Note: this is just an example, a real call would read data from their account (an account identifier is encrypted within their token) and return it.

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

As you might note, I could not access the QueryString anywhere from HttpActionContext parameter and had to build it myself. It seems like they explicitly removed QueryString from this Request object. I don’t want to add “token” it to each and every API method in order to get it in the Route Data.

So my questions are:

  1. Is the QueryString in there somewhere and I am just missing it? If not, any idea why Microsoft doesn't include it with this Request object? (i.e. maybe this is a bad thing to do?)
  2. Is there a better way to deal with getting the token in the AuthorizeAttribute (again, without adding it to each call)?

BTW, I realize there are other (probably better) options for authorization such as Basic Authentication and OAuth, and I do not want to debate that topic here.

like image 794
ThisGuy Avatar asked May 29 '13 05:05

ThisGuy


2 Answers

While Adam Tal's answer is perfectly valid, in the Web API new world order you really do not want to use anything from the System.Web namespace; in fact you don't even want to reference it. Alas you can get to the querystring from the GetQueryNameValuePairs() extension method. That will let you cut System.Web boat anchor loose and still get to what you need.

using System.Net.Http;

var queryString = actionContext.Request
        .GetQueryNameValuePairs()
        .ToDictionary(x => x.Key, x => x.Value);
like image 160
Buvy Avatar answered Nov 15 '22 17:11

Buvy


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

It works for me.

like image 26
aranjan Avatar answered Nov 15 '22 17:11

aranjan