Web API Basic Authentication
15:48Introduction
In this article I want to show how to use Basic Authentication in Web API, how it working and hosting in IIS.What Is Authentication?
Authentication is the identity of an end user. It is validating the identity of a user who is accessing our system. We use Basic Authentication technique to understand that the user able in WebAPI.What Is Authorization?
Authorization is the technique which is come after Authentication. Authorization means what all permissions the authenticated user has to access web resources. Is allowed which part the user will access in the web site. This could be achieved by setting roles and permissions for an end user who is authenticated, or can be access through providing a secure token.What Is Basic Authentication?
Basic authentication is a mechanism, where an end user gets authenticated through our Web API service i.e. RESTful service with the help of plain credentials such as user name and password. An end user makes a request to the service for authentication with user name and password. Service receives the request and checks if the credentials are valid or not, and returns the response accordingly. In case of invalid credentials, service responds with 401 error code i.e. unauthorized. The actual credentials is happend through the database or any config file like web.config or in the code itself. Here I use credentials in the code.Advantages Of Basic Authentication
1. It supported all the major browsers.2. Relatively simple protocol.
Disadvantages Of Basic Authentication
1. There have no way to log out, except by ending the browser session.2. Credentials are sent as plaintext.
3. Credentials are sent with every request.
4. Cross-site request forgery (CSRF) attacks. Requires Anti-Forgery Tokens.
What Is CSRF and Anti-Forgery Tokens?
CSRF is Cross-Site Request Forgery. Suppose you login into a website that url is www.webproject.com and its uses Form authentication. The server authenticate your credentials and send a response with authentication cookie. Now you visits a malicious web site. The malicious site HTML like this:<h1>You Are Winner Of $50000!</h1> <form action="http://webproject.com/api/account" method="post"> <input type="hidden" name="Transaction" value="withdraw" /> <input type="hidden" name="Amount" value="5000000" /> <input type="submit" value="Click Here"/> </form>So you see that the form action posts to the vulnerable site, not to the malicious site. This is the "cross-site" part of CSRF. When you click the button the request runs on the "www.webproject.com" server with your authentication context and can do anything that you can do after authenticate. Because the browser includes the authentication cookie with the request. This is Cross-site request forgery (CSRF) attacks.
To prevent Cross-site request forgery (CSRF) attacks ASP.NET MVC uses anti-forgery tokens, also called request verification tokens.
Table
CREATE TABLE Employee( [Id] [int] primary key IDENTITY(1,1) NOT NULL, [Name] [nvarchar](50) NOT NULL, [Address] [nvarchar](500) NOT NULL, [Country] [nvarchar](50) NOT NULL, [City] [nvarchar](50) NOT NULL, [Mobile] [nvarchar](10) NOT NULL )
Stored Procedure
CREATE PROCEDURE [dbo].[sp_InsUpdDelEmployee] @id int, @name nvarchar(50), @address nvarchar(500), @country nvarchar(50), @city nvarchar(50), @mobile nvarchar(50), @type varchar(10) AS Begin if(@type = 'Ins') Begin insert into Employee values(@name,@address,@country,@city,@mobile) End else if(@type = 'Upd') Begin update Employee set Name = @name, [Address] = @address, Country = @country, City = @city, Mobile = @mobile where Id = @id End else if(@type = 'Del') Begin delete from Employee where Id = @id End else if(@type = 'GetById') Begin select * from Employee where Id = @id End select * from Employee End
Step:1
Create Web API SolutionsStep:2
Build the applicationStep:3
Modified web.config in the "system.web" section.<system.web> <authentication mode="Windows" /> </system.web>Also add the bellow code in the web.config
<system.webServer> <modules runAllManagedModulesForAllRequests="true"> <add name="BasicAuthHttpModule" type="Web_API_Basic_Authentication.Modules.BasicAuthHttpModule, Web_API_IIS_Hosting" /> </modules> </system.webServer>
Step:4
Create a new class name "BasicAuthHttpModule" in the "Modules" folder.using System; using System.Collections.Generic; using System.Linq; using System.Net.Http.Headers; using System.Security.Principal; using System.Text; using System.Threading; using System.Web; namespace Web_API_Basic_Authentication.Modules { public class BasicAuthHttpModule : IHttpModule { public static string Realm = "WebAPIBasicAuthentication"; public void Init(HttpApplication context) { context.AuthenticateRequest += OnApplicationAuthenticateRequest; context.EndRequest += OnApplicationEndRequest; } private static void SetPrincipal(IPrincipal principal) { Thread.CurrentPrincipal = principal; if (HttpContext.Current != null) { HttpContext.Current.User = principal; } } private static bool AuthenticateUser(string credentials) { var encoding = Encoding.GetEncoding("iso-8859-1"); credentials = encoding.GetString(Convert.FromBase64String(credentials)); var credentialsArray = credentials.Split(':'); var username = credentialsArray[0]; var password = credentialsArray[1]; if (username == "" || password == "") { Realm = "Please enter the value properly!"; return false; } if (!(username == "surajit" && password == "coder007")) { Realm = "Username or Password Doesn't Matched!"; return false; } var identity = new GenericIdentity(username); SetPrincipal(new GenericPrincipal(identity, null)); return true; } private static void OnApplicationAuthenticateRequest(object sender, EventArgs e) { var request = HttpContext.Current.Request; var authHeader = request.Headers["Authorization"]; if (authHeader != null) { var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader); // RFC 2617 sec 1.2, "scheme" name is case-insensitive if (authHeaderVal.Scheme.Equals("basic", StringComparison.OrdinalIgnoreCase) && authHeaderVal.Parameter != null) { AuthenticateUser(authHeaderVal.Parameter); } } } private static void OnApplicationEndRequest(object sender, EventArgs e) { var response = HttpContext.Current.Response; if (response.StatusCode == 401) { response.Headers.Add("WWW-Authenticate", string.Format("Basic realm=\"{0}\"", Realm)); } } public void Dispose() { } } }
Step:5
Add Code In API ControllerNow we add "[Authorize]" attribute in the action or controller that we want to apply basic authentication. Here we apply "[Authorize]" attribute in the controller. So all the actions in the controller will apply basic authentication.
using System; using System.Collections.Generic; using System.Data.Entity.Infrastructure; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; using Web_API_IIS_Hosting_Services.Models; using System.Web.Http.Cors; using System.Web.Cors; using System.Threading.Tasks; using System.Threading; using System.Net.Http.Headers; namespace Web_API_IIS_Hosting_Services.Controllers { [Authorize] public class TestAPIController : ApiController { // Get All The Employee public ListWebApiConfig.csGet() { List emplist = new List (); using (dbEntities db = new dbEntities()) { var results = db.sp_InsUpdDelEmployee(0, "", "", "", "", "", "Get").ToList(); foreach (var result in results) { var employee = new Employee() { Id = result.Id, Name = result.Name, Address = result.Address, Country = result.Country, City = result.City, Mobile = result.Mobile }; emplist.Add(employee); } return emplist; } } // Get Employee By Id public Employee Get(int id) { using (dbEntities db = new dbEntities()) { Employee employee = db.Employees.Find(id); if (employee == null) { throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound)); } return employee; } } // Insert Employee public HttpResponseMessage Post(Employee employee) { if (ModelState.IsValid) { using (dbEntities db = new dbEntities()) { var emplist = db.sp_InsUpdDelEmployee(0, employee.Name, employee.Address, employee.Country, employee.City, employee.Mobile, "Ins").ToList(); HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, emplist); return response; } } else { return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState); } } // Update Employee public HttpResponseMessage Put(Employee employee) { List emplist = new List (); HttpResponseMessage response = null; if (!ModelState.IsValid) { return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState); } using (dbEntities db = new dbEntities()) { try { emplist = db.sp_InsUpdDelEmployee(employee.Id, employee.Name, employee.Address, employee.Country, employee.City, employee.Mobile, "Upd").ToList(); response = Request.CreateResponse(HttpStatusCode.OK, emplist); return response; } catch (DbUpdateConcurrencyException ex) { return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex); } } } // Delete employee By Id public HttpResponseMessage Delete(int id) { List emplist = new List (); HttpResponseMessage response = null; using (dbEntities db = new dbEntities()) { var results = db.sp_InsUpdDelEmployee(id, "", "", "", "", "", "GetById").ToList(); if (results.Count == 0) { return Request.CreateResponse(HttpStatusCode.NotFound); } try { emplist = db.sp_InsUpdDelEmployee(id, "", "", "", "", "", "Del").ToList(); response = Request.CreateResponse(HttpStatusCode.OK, emplist); return response; } catch (DbUpdateConcurrencyException ex) { return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex); } } } public HttpResponseMessage Options() { var response = new HttpResponseMessage(); response.StatusCode = HttpStatusCode.OK; return response; } // Prevent Memory Leak protected override void Dispose(bool disposing) { using (dbEntities db = new dbEntities()) db.Dispose(); base.Dispose(disposing); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web.Http; using System.Web.Http.Cors; namespace Web_API_Basic_Authentication { public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } } }
Step:6
Our basic authentication web api service is ready. Now run the application. You see in the browser like this:We need to provide User Name and Password to authenticate. After provide user Name "surajit" and Password "coder007" we can see the results in the browser.
0 comments