Basic Authentication in Web API Based on User Role

Oh, you still want to proceed; in other words I expect that you have both of them. Fine, we know that the Web API provides the notion of a RESTful service on top of HTTP; that is the sweet, old, important and most used protocol in the www.

One of the REST principals says that the client and server should or must be different physically and logically. What does that mean? It implies that the client and server should be very de-coupled in nature and the server will not maintain a state of the client like for a general web application normally.

So, a true RESTful service will not remember the client anymore using a state management technique like session/cookie and many more.

Now, the approach is very fine, it's a very de-coupled architecture, we can separate the client or server at any time without effecting either and the client could be any kind of application like JavaScript or any other programming language like C# or Java or even any kind of device too but the style has a great problem. Since the server does not remember the client, each and every request from the client is very new to the server and the server needs to check the request (most of the time the HTTP header) to identify the user.

So, the policy is something like this, the client will attach it's credentials along with every HTTP request and the server will check and match the credentials with some persistent storage. If the credentials match then the server will treat the HTTP request as a valid request and process it.

Yes, this is the general scenario. Now, the next point is that there are many ways to implement authentication and authorization in an application, in this article we will see how to implement basic authentication.

The principal of basic authentication is, we will send a username and password or authentication token in the header of the HTTP request and the server will parse the header to get the token.
Since we will attach sensitive data (username and password) along with every HTTP request it should be transfered in an encoded format and the protocol should be HTTPS, then we can protect our data over the internet.

Ok, so let's start the implementation. Here is my UserMaster table where I am storing the user's credentials.



I have two users with roles since we also implement authorization in the application.

Cool, we have now created a Web API application and it's time to write some code. I suggest you choose the Web API 2.0 version since I am also using that to get all the features demonstrated in this article. Once you have created it, just add one controller called “test” . Oh!! I used to use it when I tested something, please provide something meaningful in yours.

Here is the code of the controller. We see that both Get and Post are decorated with an Authorise attribute and we have specified a role over each action. So, the specific role can access a specific action. Since the Get() is to read data, generally both the Admin and the Reader can access it but a Post is only allowed for an Admin user, a reader cannot.

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Net;  
  5. using System.Net.Http;  
  6. using System.Web.Http;  
  7.   
  8. namespace WebAPI.Controllers  
  9. {  
  10.     public class testController : ApiController  
  11.     {  
  12.         [Authorize(Roles="Admin,Reader")]  
  13.         public IHttpActionResult Get()  
  14.         {  
  15.             return Ok();  
  16.         }  
  17.   
  18.         [Authorize(Roles = "Admin")]  
  19.         public IHttpActionResult Post()  
  20.         {  
  21.             return Ok();  
  22.         }  
  23.     }  
  24. }  
Cool. Now for a little more theory. If you understand the concept of a HTTP request and response pipeline in ASP.NET / Web API then it's cool. Otherwise I suggest you learn the concept because the next thing we will do is the pipeline. Here is a very quick introduction for you.

In ASP.NET / Web API a HTTP request goes through a specified pipeline, in the case of the Web API we can implement a message handler between the HTTP request and the response. So, once we implement our custom message handler in the request and response pipeline, we are done. We can implement a security mechanism like authentication and authorization in this. So, let's implement one message handler that will be derived from the Delegating handler and place it between the HTTP request and response pipeline. Just use the following procedure.

For further information of message handlers, please click here.

Now, let's implement our own message handler to check whether or not the user has sent an Authorization header along with the request, if it is presented then we will check the header value against the persistent storage, in our case it's the database table, that we have shown at first. Here is the full code sample.
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Net;  
  5. using System.Net.Http;  
  6. using System.Security.Principal;  
  7. using System.Text;  
  8. using System.Threading;  
  9. using System.Threading.Tasks;  
  10. using System.Web;  
  11. using System.Web.Http;  
  12.   
  13. namespace WebAPI  
  14. {  
  15.     public class CredentialChecker  
  16.     {  
  17.         public UserMaser CheckCredential(string username, string password)  
  18.         {  
  19.             using(var ctx = new ApiSecurityEntities())  
  20.             {  
  21.                 return ctx.UserMasers.Where(un => un.name == username && un.userpassword == password).FirstOrDefault();  
  22.             }  
  23.         }  
  24.     }  
  25.   
  26.     public class AuthenticationHandler :DelegatingHandler  
  27.     {  
  28.         protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)  
  29.         {  
  30.             try  
  31.             {  
  32.                 var tokens = request.Headers.GetValues("Authorization").FirstOrDefault();  
  33.                 if (tokens != null)  
  34.                 {  
  35.                     byte[] data = Convert.FromBase64String(tokens);  
  36.                     string decodedString = Encoding.UTF8.GetString(data);  
  37.                     string[] tokensValues = decodedString.Split(':');  
  38.   
  39.                     UserMaser ObjUser = new CredentialChecker().CheckCredential(tokensValues[0], tokensValues[1]);  
  40.                     if(ObjUser != null)  
  41.                     {  
  42.                         IPrincipal principal = new GenericPrincipal(new GenericIdentity(ObjUser.name), ObjUser.UserRole.Split(','));  
  43.                         Thread.CurrentPrincipal = principal;  
  44.                         HttpContext.Current.User = principal;  
  45.                     }  
  46.                     else  
  47.                     {  
  48.                         //The user is unauthorize and return 401 status  
  49.                         var response = new HttpResponseMessage(HttpStatusCode.Unauthorized);  
  50.                         var tsc = new TaskCompletionSource<HttpResponseMessage>();  
  51.                         tsc.SetResult(response);  
  52.                         return tsc.Task;  
  53.                     }  
  54.                 }  
  55.                 else  
  56.                 {  
  57.                     //Bad Request request because Authentication header is set but value is null  
  58.                     var response = new HttpResponseMessage(HttpStatusCode.Forbidden);  
  59.                     var tsc = new TaskCompletionSource<HttpResponseMessage>();  
  60.                     tsc.SetResult(response);  
  61.                     return tsc.Task;  
  62.                 }  
  63.                 return base.SendAsync(request, cancellationToken);  
  64.             }  
  65.             catch  
  66.             {  
  67.                 //User did not set Authentication header  
  68.                 var response = new HttpResponseMessage(HttpStatusCode.Forbidden);  
  69.                 var tsc = new TaskCompletionSource<HttpResponseMessage>();  
  70.                 tsc.SetResult(response);  
  71.                 return tsc.Task;  
  72.             }  
  73.         }  
  74.   
  75.     }  
  76. }  
Just look that if the header is not present in the HTTP request then we will consider it to be a forbidden request. If it is present then we will get the header value then decode it since we will send the header value encoded, here we will use the Base64 encoding scheme in the attached header.

So, if the credentials are present in the database then we will consider the user to be a valid user and then we will set the user principals along with the current thread.

The request will then be redirected towards a specific controller and action. Register the handler in the WebApiConfig file, just as in the following.



And we are done, now we will execute and test the application from the client and we have chosen Fillder as the client.

Now, at first let's try to access the Get action by passing an authorization header.



We are seeing that I am passing the username and password delimited by “:” and it's Base64 encoded. And the response is here:



Ok, it's a 200 and everything is fine. Now, let's change the header value to “gen:gen” and make one Post request. As a rule a general user cannot Post data in our application. So, the request should fail.



And it's throwing us an unauthorized request.



So, everything is cool and fine in the application. Now if you think that Fiddler is not the right client and you want to call the API from your application then just use the following code to call the API from the C# client.

 

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Threading.Tasks;  
  6. using System.Net.Http;  
  7. using System.Net;  
  8. using System.Net.Http.Headers;  
  9.   
  10. namespace Client  
  11. {  
  12.     class Program  
  13.     {  
  14.         static void Main(string[] args)  
  15.         {  
  16.             HttpClientHandler handler = new HttpClientHandler();  
  17.             HttpClient client = new HttpClient(handler);  
  18.             client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization","sourav:kayal");  
  19.             var result = client.GetAsync(new Uri("http://localhost:3349/api/test/")).Result;  
  20.             if (result.IsSuccessStatusCode)  
  21.             {  
  22.                 Console.WriteLine("Done" + result.StatusCode);  
  23.             }  
  24.             else  
  25.                 Console.WriteLine("Error" + result.StatusCode);  
  26.             Console.ReadLine();  
  27.         }  
  28.     }  
  29. }  
Conclusion

I hope you got the idea of basic authorization in the Web API and love this article. In the next article we will see more about API security. Thanks for reading. Have a nice day.

 


Similar Articles