Implementing authentication in HTTP message handlers
For a self-hosted web API, the best practice is to implement authentication in an HTTP Message Handler. The principal will be set by the message handler after verifying the HTTP request. For a web API that is self-hosted, consider implementing authentication in a message handler. Otherwise, use an HTTP module instead.
The following code snippet shows an example of basic authentication implemented in an HTTP module:
public class AuthenticationHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
var credentials = ParseAuthorizationHeader(request);
if (credentials != null)
{
// Check if the username and passowrd in credentials are valid against the ASP.NET membership.
// If valid, the set the current principal in the request context
var identity = new GenericIdentity(credentials.Username);
Thread.CurrentPrincipal = new GenericPrincipal(identity, null);;
}
return base.SendAsync(request, cancellationToken)
.ContinueWith(task =>
{
var response = task.Result;
if (credentials == null && response.StatusCode == HttpStatusCode.Unauthorized)
Challenge(request, response);
return response;
});
}
protected virtual Credentials ParseAuthorizationHeader(HttpRequestMessage request)
{
string authorizationHeader = null;
var authorization = request.Headers.Authorization;
if (authorization != null && authorization.Scheme == "Basic")
authorizationHeader = authorization.Parameter;
if (string.IsNullOrEmpty(authorizationHeader))
return null;
authorizationHeader = Encoding.Default.GetString(Convert.FromBase64String(authorizationHeader));
var authenticationTokens = authorizationHeader.Split(':');
if (authenticationTokens.Length < 2)
return null;
return new Credentials() { Username = authenticationTokens[0], Password = authenticationTokens[1], };
}
void Challenge(HttpRequestMessage request, HttpResponseMessage response)
{
response.Headers.Add("WWW-Authenticate", string.Format("Basic realm=\"{0}\"", request.RequestUri.DnsSafeHost));
}
public class Credentials
{
public string Username { get; set; }
public string Password { get; set; }
}
}