Some instructions on how to create implement basic authentication in a Web API application.
Just follow what is shown in the steps and screenshots as shown:
Step 1: Create a new ASP.NET Web application in Visual Studio:
Step 2: Create a new authentication filter
I have created a new folder with which to put any new filter classes:
Create a new class called BasicAuthenticationAttribute. This needs to inherit from AuthorizationFilterAttribute.
using System; using System.Net; using System.Net.Http; using System.Security.Principal; using System.Text; using System.Threading; using System.Web.Http.Filters; namespace WebApiAuthenticate.Filters { public class BasicAuthenticationAttribute : AuthorizationFilterAttribute { public override void OnAuthorization(HttpActionContext actionContext) { var authHeader = actionContext.Request.Headers.Authorization; if (authHeader != null) { var authenticationToken = actionContext.Request.Headers.Authorization.Parameter; var decodedAuthenticationToken = Encoding.UTF8.GetString(Convert.FromBase64String(authenticationToken)); var usernamePasswordArray = decodedAuthenticationToken.Split(':'); var userName = usernamePasswordArray[0]; var password = usernamePasswordArray[1]; // Replace this with your own system of security / means of validating credentials var isValid = userName == "andy" && password == "password"; if (isValid) { var principal = new GenericPrincipal(new GenericIdentity(userName), null); Thread.CurrentPrincipal = principal; actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.OK, "User " + userName + " successfully authenticated"); return; } } HandleUnathorized(actionContext); } private static void HandleUnathorized(HttpActionContext actionContext) { actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized); actionContext.Response.Headers.Add("WWW-Authenticate", "Basic Scheme='Data' location = 'http://localhost:"); } } }
Step 3: Add the filter in your WebApiConfig file
WebApiConfig.cs
using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Web.Http; using Microsoft.Owin.Security.OAuth; using Newtonsoft.Json.Serialization; using WebApiAuthenticate.Filters; namespace WebApiAuthenticate { public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API configuration and services // Web API routes config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); config.Filters.Add(new BasicAuthenticationAttribute()); } } }
Step 4: Ensure basic authentication filter is applied in Values controller
using System.Collections.Generic; using System.Net.Http; using System.Web.Http; using WebApiAuthenticate.Filters; namespace WebApiAuthenticate.Controllers { [BasicAuthentication] [RequireHttps] public class ValuesController : ApiController { // GET api/values public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } // GET api/values/5 public string Get(int id) { return id.ToString(); } // POST api/values public HttpResponseMessage Post() { var response = Request.CreateResponse<string>(System.Net.HttpStatusCode.Created, "Your first POST request!"); return response; } public HttpResponseMessage Post(int id) { var response = Request.CreateResponse<string>(System.Net.HttpStatusCode.Created, id.ToString()); return response; } // PUT api/values/5 public void Put(int id, [FromBody]string value) { } // DELETE api/values/5 public void Delete(int id) { } } }
Step 5: Create some example credentials
Example username/password credentials separated by ‘:’ are
andy:password in this example.
Obtain the Base64 encoding of “andy:password” using https://www.base64encode.org/
Giving the text “YW5keTpwYXNzd29yZA==” as shown:
Step 6: Test
Using Postman:
Using Fiddler
In the Compose window I make sure the Basic Authentication is set, along with the Base-64 encrypted username:password pair:
Host: localhost:53977
Authorization: Basic YW5keTpwYXNzd29yZA==
Content-Length: 0
On pressing the Execute button we can read the request response contained in the ‘Raw’ window:
And to allow it to return the values, just remove the response code from BasicAuthenticationAttribute class as shown:
using System; using System.Net; using System.Net.Http; using System.Security.Principal; using System.Text; using System.Threading; using System.Web.Http.Filters; namespace WebApiAuthenticate.Filters { public class BasicAuthenticationAttribute : AuthorizationFilterAttribute { public override void OnAuthorization(HttpActionContext actionContext) { var authHeader = actionContext.Request.Headers.Authorization; if (authHeader != null) { var authenticationToken = actionContext.Request.Headers.Authorization.Parameter; var decodedAuthenticationToken = Encoding.UTF8.GetString(Convert.FromBase64String(authenticationToken)); var usernamePasswordArray = decodedAuthenticationToken.Split(':'); var userName = usernamePasswordArray[0]; var password = usernamePasswordArray[1]; // Replace this with your own system of security / means of validating credentials var isValid = userName == "andy" && password == "password"; if (isValid) { var principal = new GenericPrincipal(new GenericIdentity(userName), null); Thread.CurrentPrincipal = principal; return; } } HandleUnathorized(actionContext); } private static void HandleUnathorized(HttpActionContext actionContext) { actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized); actionContext.Response.Headers.Add("WWW-Authenticate", "Basic Scheme='Data' location = 'http://localhost:"); } } }
So that on re-running the GET command in Fiddler we get the values returned as shown:
Consuming the Web Api web service from a console application
A good way of debugging your web service is to consume it from a console app.
Run the Web Api project in one instance of Visual Studio, and in another run the console application as shown:
using System; using System.Net.Http; using System.Net.Http.Headers; namespace WebApiClient { class Program { public static void Main(string[] args) { Console.WriteLine("Enter to continue"); Console.ReadLine(); DoIt(); Console.ReadLine(); } private static async void DoIt() { using (var stringContent = new StringContent("{ \"firstName\": \"Andy\" }", System.Text.Encoding.UTF8, "application/json")) using (var client = new HttpClient()) { try { client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( "Basic", Convert.ToBase64String( System.Text.Encoding.ASCII.GetBytes( string.Format("{0}:{1}", "andy", "password")))); // 1. Consume the POST command var response = await client.PostAsync("https://localhost:44363/api/values/33", stringContent); var result = await response.Content.ReadAsStringAsync(); Console.WriteLine("Result from POST command: " + result); // 2. Consume the GET command response = await client.GetAsync("https://localhost:44363/api/values/33"); if (response.IsSuccessStatusCode) { var id = await response.Content.ReadAsStringAsync(); Console.WriteLine("Result from GET command: " + result); } } catch (Exception ex) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(ex.Message); Console.ResetColor(); } } } } }
Giving the following output: