15

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.

ThisGuy
  • 2,335
  • 1
  • 28
  • 34
  • Have you tried `actionContext.Request.QueryString`. http://stackoverflow.com/questions/2219647/whats-the-difference-between-request-url-query-and-request-querystring – Satpal May 29 '13 at 05:29
  • @Satpal, yes I had assumed that property would be there when I started writing my code. But that particular Request object does not have that property. That is the crux of my question - why not? – ThisGuy May 29 '13 at 05:32
  • `actionContext.Request.RequestUri.Query` may also be useful. [http://stackoverflow.com/questions/12817202/accessing-post-or-get...](http://stackoverflow.com/questions/12817202/accessing-post-or-get-parameters-in-custom-authorization-mvc4-web-api/12828402#12828402) – Kristopher May 14 '14 at 02:43

3 Answers3

35

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);
Buvy
  • 1,174
  • 12
  • 16
  • 7
    Just to add (because it took me a second to find it), you can find this extension method by using the `System.Net.Http` namespace. – Matt Burland Aug 12 '15 at 17:58
  • 3
    Completely right. Especially if someone wants to work with vnext and get rid of System.Web. You've got my upvote :) – Adam Tal Nov 23 '15 at 23:50
12

Try

using System.Web;

HttpContext.Current.Request.QueryString
Adam Tal
  • 5,911
  • 4
  • 29
  • 49
  • Yes, that works. It was a rather long-winded question for such a such a straightforward answer... But I am still left wondering why it is not in their Request object - it is leaving me with the feeling that maybe I shouldn't be grabbing parameters off the query string in the AuthorizeAttribute. – ThisGuy May 29 '13 at 05:34
  • any ideas how to access post request – PUG Jan 29 '14 at 19:00
  • 1
    @jaminator - Try using HttpContext.Current.Request.Form dictionary which contains the post data instead of the QueryString which takes the data from the url. – Adam Tal Jan 29 '14 at 22:31
  • @AdamTal data is passed to me in json post request – PUG Jan 30 '14 at 00:02
  • @jaminator - did you try what I've suggested? – Adam Tal Jan 30 '14 at 05:47
  • @AdamTal yes i did, since there is no form sending the data from client to server rather its a json ajax call so Request.Form["somekey"] is null – PUG Jan 30 '14 at 17:14
  • @jaminator - Try the following: HttpContext.Current.Request.InputStream.Position = 0; using (var reader = new StreamReader(HttpContext.Current.Request.InputStream)) { string json = reader.ReadToEnd(); } – Adam Tal Jan 30 '14 at 20:55
1
NameValueCollection queryString = actionContext.Request.RequestUri.ParseQueryString();

It works for me.

aranjan
  • 48
  • 7