How can I retrieve Basic Authentication credentials from the header?

I am trying to write some simple tests User Authentication mechanism which uses Basic Authentication. How can I retrieve the credentials from the header?

string authorizationHeader = this.HttpContext.Request.Headers["Authorization"];

Where do I go from here? There are several tutorials but I new to .NET and authentication, could you explain in your answer exactly step-by-step the what and why you are doing.

126745 次浏览

From my blog:

This will explain in detail how this all works:

Step 1 - Understanding Basic Authentication

Whenever you use Basic Authentication a header is added to HTTP Request and it will look similar to this:

Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

Source: http://en.wikipedia.org/wiki/Basic_access_authentication

"QWxhZGRpbjpvcGVuIHNlc2FtZQ==" is just "username:password" encoded in Base64(http://en.wikipedia.org/wiki/Base64). In order to access headers and other HTTP properties in .NET (C#) you need to have access to the current Http Context:

HttpContext httpContext = HttpContext.Current;

This you can find in System.Web namespace.

Step 2 - Getting the Header

Authorization header isn't the only only one in the HttpContext. In order to access the header, we need to get it from the request.

string authHeader = this.httpContext.Request.Headers["Authorization"];

(Alternatively you may use AuthenticationHeaderValue.TryParse as suggested in pasx’s answer below)

If you debug your code you will see that the content of that header looks similar to this:

Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

Step 3 - Checking the header

You've already extracted the header now there are several things you need to do:

  1. Check that the header isn't null
  2. Check that the Authorization/Authentication mechanism is indeed "Basic"

Like so:

if (authHeader != null && authHeader.StartsWith("Basic")) {
//Extract credentials
} else {
//Handle what happens if that isn't the case
throw new Exception("The authorization header is either empty or isn't Basic.");
}

Now you have check that you are have something to extract data from.

Step 4 - Extracting credentials

Removing "Basic " Substring

You can now attempt to get the values for username and password. Firstly you need to get rid of the "Basic " substring. You can do it like so:

string encodedUsernamePassword = authHeader.Substring("Basic ".Length).Trim();

See the following links for further details:

  1. http://msdn.microsoft.com/en-us/library/system.string.substring(v=vs.110).aspx
  2. http://msdn.microsoft.com/en-us/library/t97s7bs3(v=vs.110).aspx

Decoding Base64

Now we need to decode back from Base64 to string:

//the coding should be iso or you could use ASCII and UTF-8 decoder
Encoding encoding = Encoding.GetEncoding("iso-8859-1");
string usernamePassword = encoding.GetString(Convert.FromBase64String(encodedUsernamePassword));

Now username and password will be in this format:

username:password

Splitting Username:Password

In order to get username and password we can simply get the index of the ":"

int seperatorIndex = usernamePassword.IndexOf(':');


username = usernamePassword.Substring(0, seperatorIndex);
password = usernamePassword.Substring(seperatorIndex + 1);

Now you can use these data for testing. Good luck!

The Final Code

The final code may look like this:

HttpContext httpContext = HttpContext.Current;


string authHeader = this.httpContext.Request.Headers["Authorization"];


if (authHeader != null && authHeader.StartsWith("Basic")) {
string encodedUsernamePassword = authHeader.Substring("Basic ".Length).Trim();
Encoding encoding = Encoding.GetEncoding("iso-8859-1");
string usernamePassword = encoding.GetString(Convert.FromBase64String(encodedUsernamePassword));


int seperatorIndex = usernamePassword.IndexOf(':');


var username = usernamePassword.Substring(0, seperatorIndex);
var password = usernamePassword.Substring(seperatorIndex + 1);
} else {
//Handle what happens if that isn't the case
throw new Exception("The authorization header is either empty or isn't Basic.");
}

Awesome answer from @DawidO.

If you are just looking to extract the basic auth creds and rely on the .NET magic given you have HttpContext, this will also work:

  public static void StartListener() {
using (var hl = new HttpListener()) {
hl.Prefixes.Add("http://+:8008/");
hl.AuthenticationSchemes = AuthenticationSchemes.Basic;
hl.Start();
Console.WriteLine("Listening...");
while (true) {
var hlc = hl.GetContext();


var hlbi = (HttpListenerBasicIdentity)hlc.User.Identity;
Console.WriteLine(hlbi.Name);
Console.WriteLine(hlbi.Password);


//TODO: validater user
//TODO: take action
}
}
}

Remember, using strings can be less secure. They will remain in memory untill they are picked by GC.

Just adding to the main answer, the best way to get rid of the "Basic" substring is to use AuthenticationHeaderValue Class:

var header = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
var credentials = header.Parameter;

It will throw a FormatException if the content of the header is not valid, e.g.: the "Basic" part is not present.

Alternatively if you do not want to have exception, use AuthenticationHeaderValue.TryParse