Tuesday, 6 March 2018

Web API 2- token based authentication

ASP.NET Web API can be accessed over Http by any client using the Http protocol. Typically, in a Line of Business (LOB) application, using Web API is a standard practice now-a-days. This framework enables data communication in JSON format (by default) and hence helps in lightweight communication.
  In token-based authentication, you pass your credentials [user name and password], which go to authentication server. Server verifies your credentials and if it is a valid user then it will return a signed token to client system, which has expiration time. Client can store this token to locally using any mechanism like local storage, session storage etc and if client makes any other call to server for data then it does not need to pass its credentials every time. Client can directly pass token to server, which will be validated by server and if token is valid then you will able to access your data.
How token based authentication actually works?
In the Token based approach, the client application first sends a request to Authentication server endpoint with an appropriate credential. Now If the username and password are found correct then the Authentication server send a token to the client as a response. This token contains enough data to identify a particular user and an expiry time.The client application then uses the token to access the restricted resources in next requests till the token is valid.

In this article, I have used Visual Studio 2015


1:- Create New Project.
Go to the file menu > create > projet > select "asp.net web application" under web > enter application name > select your project location > and then click on add button

    It will bring up a new dialog window for select template > here I will select empty template > and then checked MVC & Web API checkbox from Add folder and core references for > and then click on Ok button.

We are using OWIN [Open Web Interface for .Net] that is an interface between your web server and web application. So, it works as a middle ware in applications, which process your incoming request and validate it. Here we are using AuthServerProvider, which is nothing but a class which validate user based on their credentials. You can find this class below.

2: Add required references from NuGet packages into our application.
To Implement token based authentication in WEB API, we need to install followings references from NuGet packages
  • Microsoft.Owin.Host.SystemWeb
  • Microsoft.Owin.Security.OAuth
  • Microsoft.Owin.Cors
for adding following resources from NuGet, Go to Solution Explorer >  Right Click on References > Click on Manage NuGet packages > Search for the Microsoft.Owin.Host.SystemWeb, Microsoft.Owin.Security.OAuth & Microsoft.Owin.Cors and install.

3: Add a class for validating user credentials asking for tokens.

add a class in our application for validate the credentials for users and generate token.

In this class we will inherit "OAuthAuthorizationServerProvider" class for  overriding 2 methods "ValidateClientAuthentication" and "GrantResourceOwnerCredentials".

"ValidateClientAuthentication" method is used for validating client app (for the sake of simplicity, we will  deep dive on "ValidateClientAuthentication" method later) and in the "GrantResourceOwnerCredentials"  method we will validate the credentials of users and if we found valid credential, we will generate the signed token, using which user can access authorized resources of server.

AuthServerProvider.cs
using Microsoft.Owin.Security.OAuth;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web;

namespace WebApiTokenBasedAuth
{
    public class AuthServerProvider: OAuthAuthorizationServerProvider
    {
        public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            context.Validated(); 
        }

        public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
            var identity = new ClaimsIdentity(context.Options.AuthenticationType);
            if (context.UserName == "admin" && context.Password == "admin")
            {
                identity.AddClaim(new Claim(ClaimTypes.Role, "admin"));
                identity.AddClaim(new Claim("username", "admin"));
                identity.AddClaim(new Claim(ClaimTypes.Name, "Suraj Mad. Admin"));
                context.Validated(identity);
            }
            else if (context.UserName == "user" && context.Password == "user")
            {
                identity.AddClaim(new Claim(ClaimTypes.Role, "user"));
                identity.AddClaim(new Claim("username", "user"));
                identity.AddClaim(new Claim(ClaimTypes.Name, "Suraj Mad."));
                context.Validated(identity);
            }
            else
            {
                context.SetError("invalid_grant", "Provided username and password is incorrect");
                return;
            }
        }
    }
}

4: Add Owin Start Up class.

Now we will add OWIN Startup class. This is the startup class used to configure application startup.
It accepts IAppBuilder interface to manage middleware for the application. In this case it is OWIN. This function uses the OAuthAuthorizationServerOptions class which provides the information needed to control Authorization server middleware behavior. The code sets some properties for this class.
Go to Solution Explorer > Right Click on Project Name form Solution Explorer > Add > New Item > Select OWIN Startup class > Enter class name > Add.

Startup.cs
using System;
using Microsoft.Owin;
using Owin;
using Microsoft.Owin.Security.OAuth;
using System.Web.Http;

[assembly: OwinStartup(typeof(WebApiTokenBasedAuth.Startup))]
namespace WebApiTokenBasedAuth
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            //enable cors origin requests
            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
            var myProvider = new WebApiTokenBasedAuth.AuthServerProvider();
            OAuthAuthorizationServerOptions options = new OAuthAuthorizationServerOptions
            {
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
                Provider = myProvider
            };
            app.UseOAuthAuthorizationServer(options);
            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

            HttpConfiguration config = new HttpConfiguration();
            WebApiConfig.Register(config);
        }
    }
}

In the above class we need the following important properties

· TokenEndPointPath - The client application communicates as part of the OAuth protocol. To complete the login with the token, /Token is used. The grant_type must be shared by the client to complete the login using access token generated by the server.

· AccessTokenExpirationTimeSpan - This is the time span for the life of the authorization token after being issued.

· Provider - The value for the property is set by the OAuthorizationServerProvider object. This class is responsible for providing behavior to requests. This is used to validate client authentication, claims etc.

AllowInsecureHttp - This is a Boolean property used to allow authorize and token requests to arrive on http URI address.

5: Add an another Class for override authorize attribute.

When building an HTTP REST API, we should use appropriate HTTP response codes to indicate the status of a response. I always use 401 and 403 status code for getting authentication/authorization status. 401 (Unauthorized) - indicates that the request has not been applied because it lacks valid authentication credentials for the target resource. and 403 (Forbidden) - when the user is authenticated but isn’t authorized to perform the requested operation on the given resource.

Unfortunately, the ASP.NET MVC/Web API [Authorize] attribute doesn’t behave that way – it always emits 401. So, here in our Web API application, I am going to add a class for override this behavior. Here we will return 403 when the user is authenticated but not authorized to perform the requested operation.

AuthorizeAttribute.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace WebApiTokenBasedAuth
{
    public class AuthorizeAttribute: System.Web.Http.AuthorizeAttribute
    {
        protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
        {
            if (!HttpContext.Current.User.Identity.IsAuthenticated)
            {
                base.HandleUnauthorizedRequest(actionContext);
            }
            else
            {
                actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
            }
        }
    }
}

6: Add WEB API Controller. 
Add a WEB API Controller , Where we will add some action So we can check the token authentication is working fine or not.


7: Add an action for getting data from the server for all anonymous user.
I have added this action for all anonymous users. All type of request, whether it is authenticated or not can access this action.

        [AllowAnonymous]
        [HttpGet]
        [Route("api/MyWebApi/GetAll")]
        public IHttpActionResult Get()
        {
            return Ok("Now server time is: " + DateTime.Now.ToString());
        }

8: Add an another action for getting data from the server for all authenticated user.
I have added this action for all type of authenticated users, whether it is Admin user or normal user.

        [Authorize]
        [HttpGet]
        [Route("api/MyWebApi/authenticate")]
        public IHttpActionResult GetForAuthenticate()
        {
            var identity = (ClaimsIdentity)User.Identity;
            return Ok("Hello " + identity.Name);
        }

9: Add an another action for getting data from the server only for Admin user.
I have added this action only for Admin role type users.


        [Authorize(Roles = "admin")]
        [HttpGet]
        [Route("api/MyWebApi/authorize")]
        public IHttpActionResult GetForAdmin()
        {
            var identity = (ClaimsIdentity)User.Identity;
            var roles = identity.Claims
                        .Where(c => c.Type == ClaimTypes.Role)
                        .Select(c => c.Value);
            return Ok("Hello " + identity.Name + " Role: " + string.Join(",", roles.ToList()));
        }

10: Run Application.
Our WEB API Configuration is ready, Now we will test our application with POSTMAN

Postman is an extension of Chrome, which is used as a client application to test the request and response between web service and client.

Test 1:
Select GET (see below picture section 1),  Enter this url http://localhost:/api/MyWebApi/GetAll  and then click on send button.

We will get 200 OK status code (see section 3 in the below picture) and the result in the section 4 in that picture. That means our first action working fine when the request is anonymous.


But now if we try to access our 2nd action (GetForAuthenticate with url : http://localhost:52381/api/MyWebApi/authenticate) then we will get 401 Unauthenticated because the request is not authenticated yet. It will same for the 3rd action also.


So, what we need to access the 2nd and 3rd action? We need access token from server first and then we can access the 2nd and 3rd action with that access token.

Test 2 : Getting access token.
Select POST (in section 1),  Enter this URL http://localhost:/token (in section 2) and then click on body (in section 3) and select select x-www-form-urlencoded and then enter 3 parameter, 1. username (value : user) 2. password (value: user) and 3. grant_type (value: password) and then click on  send button. After click on send button we will get 200 OK (see section 4) and access token (see section 5)


Now we can access http://localhost:52381/api/MyWebApi/authenticate with that access token.

Test 3: Access restricted resource with access token.

Select GET(in section 1),  Enter this URL http://localhost:52381/api/MyWebApi/authenticate (in section 2) and then click on Headers(in section 3) and enter 1 parameter, Authorization (value : Bearer) and then click on  send button. After click on send button we will get 200 OK (see section 4) and the result (see section 5).

In the same way, we can access our 3rd action but we have to get token logged in with username : admin and password: admin because the 3rd action accessible only for Admin role user.



0 comments:

Post a Comment

Topics

ADO .Net (2) Ajax (1) Angular Js (17) Angular2 (24) ASP .Net (14) Azure (1) Breeze.js (1) C# (49) CloudComputing (1) CMS (1) CSS (2) Design_Pattern (3) DI (3) Dotnet (21) Entity Framework (3) ExpressJS (4) Html (3) IIS (1) Javascript (6) Jquery (9) Lamda (3) Linq (11) Mongodb (1) MVC (48) NodeJS (7) RDLC (1) Report (1) Sql Server (29) SSIS (3) SSRS (2) UI (1) WCF (12) Web Api (9) Web Service (1) XMl (1)