Introduction
In this article, we will learn about basic authentication of ASP.NET WebAPI 2.0 and generating requests from Postman and Ajax.
Since WebAPI is on RESTFUL architecture, WebAPI plays an important role in handling server-side requests without storing the states on either the frontend or backend. WebAPI supports the backend of any type of application, such as mobile, web, etc., with basic http protocol.
To keep the WebAPI secure from unauthorized users, authentication comes into the picture, since the endpoints of the WebAPI can be easily accessible from the frontend.
There are multiple ways to secure the WebAPI with the following processes:
- JSON Web Token(JWT)
- Basic Authentication
In this article, we will discuss Basic Authentication. It is the easiest and most conventional way to authorize the user in requests and provide access to perform operations.
In Basic Authentication, the user passes their credentials [user name and password] on a post request. At the WebAPI end, credentials are verified. If the credentials are valid, then a session will initiate to accept the subsequent requests without validating the user again. If the credentials are not valid, then WebAPI returns the 401 unauthorized httpstatuscode.
In this article, we will create ASP.NET WebApi 2.0 and use Postman for testing endpoints.
We will also create a project and request WebAPI for data using Ajax.
Let's start.
Create Databases and Tables
Create a Database and two tables. One is for User credentials and another one is for data.
Create a new ASP.NET Web API 2.0 project
Open Visual Studio and select the file option to create a .NET standard project. Select a WebAPI with "No Authentication".
Create a connection with Database
Right-click your WebApi project and Add a new item. Select ADO.NET Entity Data Model and make a new connection with the database. Select both the database table for validating users and fetching data.
Create a new Class
Create a class that contains a static method with the boolean return type to check whether the user is authenticated or not. I used OrdinalIgnoreCase to ignore the alphabet case in the username.
- {
- using(testEntities entity = new testEntities()) {
- return entity.tblLogins.Any(x => x.username.Equals(uname, StringComparison.OrdinalIgnoreCase) && x.pass == pass);
- }
- }
Create another new Class
Add a new class to retrieve the username and password which is coming through the post request with Base64encoding. The username and password will come with colon-separated.
Add a new class to create a custom Authorization filter in which username and password will validate and allow or deny the requests. The “AuthorizationFilterAttribute” class needs to be inherited so that the “OnAuthorization” method can be overridden.
To use the custom Authorization filter class, add the [customAuthorizedClass] attribute over the controller or action. Once the request comes to that controller, first the user credentials will be checked to see if they are valid. Then, the Username is saved in Thread.CurrentPrincipal to maintain the session. Otherwise, it returns a 401 unauthorized httpstatuscode.
- public class BasicAuthenticationAttribute: AuthorizationFilterAttribute {
- public override void OnAuthorization(HttpActionContext actionContext) {
- if (actionContext.Request.Headers.Authorization == null) {
- actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
- } else {
- string authenticationToken = actionContext.Request.Headers.Authorization.Parameter;
- string decodedAuthenticationToken = Encoding.UTF8.GetString(Convert.FromBase64String(authenticationToken));
- string[] usernamePasswordArray = decodedAuthenticationToken.Split(':');
- string uname = usernamePasswordArray[0];
- string pass = usernamePasswordArray[1];
- if (EmployeeSecurity.Login(uname, pass)) {
- Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(uname), null);
- } else {
- actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
- }
- }
- }
- }
Create a new Controller
Create a new controller to get data from the database and use [customAuthorizeClass] attribute to validate the user.
If Thread.CurrentPrincipal is not blank, then the controller gives HttpStatusCode 200 which is OK along with the requested data. Otherwise, the controller gives HttpStatusCode 401, which is an unauthorized user message.
- public class Employees Controller: ApiController {
- [HttpGet]
- [BasicAuthentication]
- public HttpResponseMessage Get() {
- string userName = Thread.CurrentPrincipal.Identity.Name;
- using(testEntities entities = new testEntities()) {
- if (userName != "") {
- return Request.CreateResponse(HttpStatusCode.OK, entities.EmployeeLists.Select(x => x.EmpName).ToList());
- } else {
- return Request.CreateResponse(HttpStatusCode.Unauthorized);
- }
- }
- }
- }
Build the application and run(F5). It will give a 401 unauthorized error.
Calls from Postman
Open Postman to test whether our WebApi is working as we expected or not.
Create a GET request from Postman by select Get and enter WebApi's Controller URL "api/employee" and select Basic Auth in an Authorization header. Enter credentials and press send.
If the credentials user entered is correct then the output will be shown on the body of Postman with HttpStatus 200.
If the credentials user entered is not correct, then the HttpStatus 401 will be shown.
We checked and our WebAPI is working fine with Postman.
Now we will see how we can make HTTP calls through AJAX from a different project.
Create another Project
Right-click on the solution, select Add a new empty project.
Add a new HTML page by right-clicking on the newly created project.
Give the reference of the jquery file to support Ajax. Create two input fields, one is for username and the other is for a password with a button.
On document.ready(), write an Ajax script on a Button click event. Use the btoa function in the Authorization header to convert username and password in Binary to ASCII for Base64encoding.
A successful run will display data on the UI and on completion display HttpStatusCode message on UI.
Set this project as a Startup project and HTML page as the Startup Page.
If we run our project and make an Ajax call, it will not give output because the WebAPI is hosted on a different domain and Ajax makes a call from a different domain that is not reachable.
To make it work we need to download CORS (Cross origin resource sharing) module from Nuget Manager for that project.
After downloading, write EnableCors attribute in the WebApiConfig.cs file and mention "*" for origin, header and domain.
You can specify your project's domain as well in the place of "*" which makes your WebApi not work with other domains.
- <scripttype = "text/javascript" > $(document).ready(function() {
- var ulEmployee = $('#ulEmployee');
- $('#submit').click(function() {
- var uname = $('#username').val();
- var pass = $('#password').val();
- $.ajax({
- type: 'GET',
- url: "http://localhost:53002/Api/Employees",
- datatype: 'json',
- headers: {
- 'Authorization': 'Basic ' + btoa(uname + ':' + pass)
- },
- success: function(data) {
- ulEmployee.empty();
- $.each(data, function(index, val) {
- ulEmployee.append('<li>' + val + '</li>');
- });
- },
- complete: function(jqXHR) {
- if (jqXHR.status == '401') {
- ulEmployee.empty();
- ulEmployee.append('<li>' + jqXHR.statusText + '</li>');
- }
- }
- });
- });
- });
- </script>
- public static void Register(HttpConfiguration config) {
-
-
- config.MapHttpAttributeRoutes();
- config.Routes.MapHttpRoute(name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new {
- id = RouteParameter.Optional
- });
- EnableCorsAttribute enableCors = new EnableCorsAttribute("*", "*", "*");
- config.EnableCors(enableCors);
- }
You see how easy is to implement Basic Authentication on WebAPI 2.0!
I hope your application will give you the desired output.
Thanks
Keep Learning :)