3

I am developing a web site using the following technologies:

MVC 4 EF 5 Web Api Future - possible Windows Phone/Windows 8 application.

I am using Web API so that I have a developed api that I can use on other clients.

However, I will need to authorise the user each time a request is made to the API. My initial thought was to do this via the HTTP headers. However, I'm just wondering if I should just use MVC Controllers instead of Web API for the MVC application and create a RESTful api if I was to develop a phone/win 8 application, again the user would need to be authenticated. So the originally problem still exists.

What are people's thoughts? Can any one point me to a tutorial on how I could securely pass the authenticated users details over the HTTP Header, also something that's a step by step tutorial as I'm going into this from scratch and need to understand it.

j0k
  • 22,600
  • 28
  • 79
  • 90
dotnethaggis
  • 1,000
  • 12
  • 26
  • Is this what you are looking for? http://stackoverflow.com/questions/11014953/asp-net-mvc-4-webapi-authentication – user1797792 Jan 03 '13 at 12:26

1 Answers1

1

I use basic authentication to pass the credentials for authorization. This puts the credentials in the header. To do this is pretty straight forward by using the beforeSend event handler of the JQuery ajax function. Here is an example of how to do this.

    getAuthorizationHeader = function (username, password) {
      var authType;
      var up = $.base64.encode(username + ":" + password);
      authType = "Basic " + up;
    };
    return authType;
 };

    $.ajax({
        url: _url,
        data: _data,
        type: _type,
        beforeSend: function (xhr) {
            xhr.setRequestHeader("Authorization", getAuthorizationHeader(username, password));
        },
        success: ajaxSuccessHandler,
        error: ajaxErrHandler
    });

This encodes the username/password that is sent in the header. Note that this is not enough security to rely on just the encoding as it is easy to decode. You still want to use HTTPS/SSL to make sure the information sent over the wire is secure.

On the Web API side you can make a custom AuthorizeAttribute that gets the credentials from the header, decodes them, and performs your authorization process. There is a separate AuthorizeAttribute used by the Web API as opposed to the controller. Be sure to use System.Web.Http.AuthorizeAttribute as your base class when creating your custom AuthorizeAttribute. They have different behaviors. The one for the controller will want to redirect to the logon page whereas the one for the Web API returns an HTTP code indicating success or failure. I return an HTTP code of Forbidden if authorization fails to distinguish a failure due to authorization as opposed to authentication so the client can react accordingly.

Here is an example method for getting the credentials from the header that can be used in the custom AuthorizeAttribute.

    private bool GetUserNameAndPassword(HttpActionContext actionContext, out string username, out string password)
    {
        bool gotIt = false;
        username = string.Empty;
        password = string.Empty;
        IEnumerable<string> headerVals;
        if (actionContext.Request.Headers.TryGetValues("Authorization", out headerVals))
        {
            try
            {
                string authHeader = headerVals.FirstOrDefault();
                char[] delims = { ' ' };
                string[] authHeaderTokens = authHeader.Split(new char[] { ' ' });
                if (authHeaderTokens[0].Contains("Basic"))
                {
                    string decodedStr = SecurityHelper.DecodeFrom64(authHeaderTokens[1]);
                    string[] unpw = decodedStr.Split(new char[] { ':' });
                    username = unpw[0];
                    password = unpw[1];
                }
                gotIt = true;
            }
            catch { gotIt = false; }
        }

        return gotIt;
    }

And here is the code for decoding the header data that is used in this method.

    public static string DecodeFrom64(string encodedData)
    {

        byte[] encodedDataAsBytes

            = System.Convert.FromBase64String(encodedData);

        string returnValue =

           System.Text.Encoding.ASCII.GetString(encodedDataAsBytes);

        return returnValue;

    }

Once you have the username and password you can perform your authorization process and return the appropriate HTTP code to the client for handling.

Updated 3/8/2013

I wrote a blog post that goes into more details on how to implement this with SimpleMembership, the default membership provider for MVC 4 Internet Applications. It also includes a downloadable VS 2012 project that implements this.

Kevin Junghans
  • 17,475
  • 4
  • 45
  • 62
  • Thanks for this, what if I was wanting to check on each server call that the user is authenticated - they aren't going to provide their password each time...? – dotnethaggis Mar 05 '13 at 14:38
  • If the client supports cookies you can use them. When you authenticate the user set the cookie. Then in your logic for authentication/authorization if the credentials are not in the header you can try using the cookie to authenticate. There is more details on using this with SimpleMembership provider here [http://kevin-junghans.blogspot.com/2013/02/mixing-forms-authentication-basic.html] – Kevin Junghans Mar 06 '13 at 13:49
  • Excellent - thank you very much Kevin. I will read this in due course. – dotnethaggis Mar 08 '13 at 13:16
  • It looks like the link in the comment is broken (extra "]" char at the end), and I cannot edit it. I updated the answer to include the link at the end. – Kevin Junghans Mar 08 '13 at 14:10