Securing ASP.NET Web API using Token Based Authentication and using it in AngularJS application

Hesam Seyed Mousavi, December 25, 2016

hesam_seyed_mousavi_securing-asp-net-web-api

By: Mahesh Sabnis

Source: ItpTechMag

blog.mousavi.fr

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.

Token Based Authentication

Since the Web API adoption is increasing at a rapid pace, there is a serious need for implementing security for all types of clients trying to access data from Web API services. One of the most preferred mechanism is to authenticate client over HTTP using a signed token. Simply put, a token is a piece of data which is created by a server, and which contains enough data to identify a particular user. The process starts by allowing users to enter their username and password which accessing a service. Once the user provides the username/password, a token is issued which allows users to fetch a specific resource – without using their username and password every time. This token is sent to the server with each request made by the client and contains all necessary information to validate a user’s request. The following diagram explains how Token-Based authentication is used in communication between clients and server.

token-based-auth-working

Advantages of Token Based Authentication

· The client application is not dependent on a specific authentication mechanism. The token is generated by the server and the Web API have some APIs to understand, validate the token and perform the authentication. This approach provides Loose Coupling between client and the Web API.

· Maintaining cookies in native mobile applications is not an easy task. Using token based authentication, we can now provide support for mobile applications with much ease.

In the current application, we will use a Web API project created using Visual Studio 2015 and Angular.js as a client application.

The implementation

Step 1: Open VS 2015 and create a Web API project of name ‘WebAPI_NG_TokenbasedAuth’ as shown in the following image:

create-webapi-project

Make sure that, the Authentication option is selected as Individual User Accounts. This is because we will register users using the method of the AccountController class which will be created in the Web API project using the above template.

Once the project is created, open the web.config file. This will contain the connectionStrings section. This section stores the database connection for the database which will be created for tables storing user’s information. The value of the connection string will be as shown here:

<add name="DefaultConnection"
connectionString="Data Source=(LocalDb)\MSSQLLocalDB;
AttachDbFilename=|DataDirectory|\aspnet-WebAPI_NG_TokenbasedAuth-20151001025617.mdf;
Initial Catalog=aspnet-WebAPI_NG_TokenbasedAuth-20151001025617;
Integrated Security=True" providerName="System.Data.SqlClient" />

Expand project references to view the assembly references for Google, Facebook, and Twitter that use the token for user authentication. The project contains Startup.cs class file. This is the startup class used to configure application startup. The class contains a Configuration() method which calls the ConfigureAuth() method implemented in Startup.Auth.cs file of the App_Start folder.

[assembly: OwinStartup(typeof(WebAPI_NG_TokenbasedAuth.Startup))]
namespace WebAPI_NG_TokenbasedAuth
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            ConfigureAuth(app);
        }
    }
}

The ConfigureAuth() method 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.

public void ConfigureAuth(IAppBuilder app)
{
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext(ApplicationUserManager.Create);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
    TokenEndpointPath = new PathString("/Token"),
    Provider = new ApplicationOAuthProvider(PublicClientId),
    AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
    AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
    // In production mode set AllowInsecureHttp = false
    AllowInsecureHttp = true
};
app.UseOAuthBearerTokens(OAuthOptions);
}

In our application 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. We have used the Visual Studio Web API template. The implementation for the class derived from OAuthorizationServerProvider class can be found from the Providers folder in the project.

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

The code finally calls UseOAuthBearerTokens() method which accepts the OAuthAuthorizationServerOptions object as input parameter to enable the application to use bearer token to authenticate a user.

Step 2: Open the AccountController class from the Controllers folder. This is the ApiController class for user registration.

[AllowAnonymous]
[Route("Register")]
public async Task Register(RegisterBindingModel model)
{
…….
}

We will call this method from our Angular.js application to register a user.

Step 3: Since we are designing the application to access data from Web API using token based authentication, we need to add some model logic to our application. In the Models folder, add an EmployeeModel.cs class file with the following logic:

using System.Collections.Generic;
namespace WebAPI_NG_TokenbasedAuth.Models
{
    public class Employee
    {
        public int EmpNo { get; set; }
        public string EmpName { get; set; }
        public int Salary { get; set; }
        public string DeptName { get; set; }
    }
    public class EmployeeDatabase : List
    {
        public EmployeeDatabase()
        {
            Add(new Employee() { EmpNo = 101, EmpName = "TS", Salary = 12000, DeptName = "IT" });
            Add(new Employee() { EmpNo = 102, EmpName = "MS", Salary = 22000, DeptName = "System" });
            Add(new Employee() { EmpNo = 103, EmpName = "LS", Salary = 21000, DeptName = "Sales" });
            Add(new Employee() { EmpNo = 104, EmpName = "VB", Salary = 32000, DeptName = "HRD" });
            Add(new Employee() { EmpNo = 105, EmpName = "PB", Salary = 42000, DeptName = "HRD" });
            Add(new Employee() { EmpNo = 106, EmpName = "AB", Salary = 12000, DeptName = "Admin" });
        }
    }
}

The above class file contains Employee and EmployeeDatabase class with default data.

Step 4: In the Controllers folder, add an Empty Web API Controller class of name EmployeeAPIController. Add the following code in it:

[Authorize]
public class EmployeeAPIController : ApiController
{
    public List Get()
    {
        return new EmployeeDatabase();
    }
}

The above class is applied with the Authorize attribute. This is the Authorize filter to make sure that the HTTP GET request for the Web API will be executed only for authenticated users.

Step 5: In the Controllers folder, add a new Empty MVC Controller class of name EmployeeController. This will contain an Index () action method. We will use this action method to generate the Index.cshtml view for displaying all employees.

public class EmployeeController : Controller
{
    // GET: Employee
    public ActionResult Index()
    {
        return View();
    }
}

Scaffold an empty Index.cshtml view from this Index action method. We will use this view very shortly with the HTML markup code.

Step 6: In the Controllers folder, add a new Empty MVC controller of name LoginController, add the following code in it:

[AllowAnonymous]
public class LoginController : Controller
{
    // GET: Login
    public ActionResult SecurityInfo()
    {
        return View();
    }
}

The above controller contains SecurityInfo() action method. Scaffold an empty SecurityInfo.cshtml view from this action method. We will design this view in future for User Registration and Login.

Implementing the Client-Side logic

We will use Angular.js and Bootstrap for client-side logic and UI design respectively. We will also make use of HTML 5 sessionStorage object to maintain the Token on the client-side. To install angular and bootstrap, we will use NuGet Package manager.

Step 1: Right click on the project and select Manage NuGet Packages.. option. This will open the NuGet Package manager window. Search for Angular.js and Bootstrap from this window. Alternatively, execute the following commands from Tools > NuGet Package Manager > Package Manager Console:

Install-Package angularjs
Install-Package bootstrap -Version 3.3.5

This will add Scripts folder in the project with required Angular.js, jQuery and Bootstrap scripts.

Step 2: In the Scripts folder, add a new folder of name MyScripts. In this folder we will add scripts for our client-side logic.

Module.js

var app;
app = angular.module('appmodule',[]);

This is an Angular module of name ‘appmodule’.

LoginLogic.js

//1.
app.service('loginservice', function ($http) {
    this.register = function (userInfo) {
        var resp = $http({
            url: "/api/Account/Register",
            method: "POST",
            data: userInfo,
        });
        return resp;
    };
    this.login = function (userlogin) {
        
        var resp = $http({
            url: "/TOKEN",
            method: "POST",
            data: $.param({ grant_type: 'password', username: userlogin.username, password: userlogin.password }),
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        });
        return resp;
    };
});
//2.
app.controller('logincontroller', function ($scope, loginservice) {
    //Scope Declaration
    $scope.responseData = "";
    $scope.userName = "";
    $scope.userRegistrationEmail = "";
    $scope.userRegistrationPassword = "";
    $scope.userRegistrationConfirmPassword = "";
    $scope.userLoginEmail = "";
    $scope.userLoginPassword = "";
    $scope.accessToken = "";
    $scope.refreshToken = "";
    //Ends Here
    //Function to register user
    $scope.registerUser = function () {
        
        $scope.responseData = "";
        //The User Registration Information
        var userRegistrationInfo = {
            Email: $scope.userRegistrationEmail,
            Password: $scope.userRegistrationPassword,
            ConfirmPassword: $scope.userRegistrationConfirmPassword
        };
        
        var promiseregister = loginservice.register(userRegistrationInfo);
        promiseregister.then(function (resp) {
            $scope.responseData = "User is Successfully";
            $scope.userRegistrationEmail="";
            $scope.userRegistrationPassword="";
            $scope.userRegistrationConfirmPassword="";
        }, function (err) {
            $scope.responseData="Error " + err.status;
        });
    };
    $scope.redirect = function () {
        window.location.href = '/Employee/Index';
    };
    //Function to Login. This will generate Token
    $scope.login = function () {
        //This is the information to pass for token based authentication
        var userLogin = {
            grant_type: 'password',
            username: $scope.userLoginEmail,
            password: $scope.userLoginPassword
        };
        var promiselogin = loginservice.login(userLogin);
        promiselogin.then(function (resp) {
            
            $scope.userName = resp.data.userName;
            //Store the token information in the SessionStorage
            //So that it can be accessed for other views
            sessionStorage.setItem('userName', resp.data.userName);
            sessionStorage.setItem('accessToken', resp.data.access_token);
            sessionStorage.setItem('refreshToken', resp.data.refresh_token);
            window.location.href = '/Employee/Index';
        }, function (err) {
            
            $scope.responseData="Error " + err.status;
        });
    };
});

The above JavaScript logic is the center for our complete application. This contains the following specifications:

1. The logicservice is an Angular.js service. This service contains the following functions:

a. register() calls the Account Web API and its Register action method. This is the POST call to register new application user based on userInfo passed to it.

b. login() calls /TOKEN url and passes the user information. This return the access_token when the call is complete. Here it uses grant_type as password to get the access token using password grant when the user logs in.

2. The logincontroller is the angular controller used to define scope objects with data-binding. This has the following specifications:

a. Defines scope declarations for user registration information like Email, Password, confirm password along with LoginEmail and LoginPassword which will be used during the login process. This also defines scope objects for Access token and refresh token.

b. The registerUser() function contains logic for user registration. This defines userRegistrationInfo object which will be passed to the register () function of the loginservice.

c. The login() function is used to call login() function of the loginservice. This passes the userLogin object containing LoginEmail, LoginPassword and grant_type as password to the login() function. Once the call is successfully completed, the access token will be returned which will be stored in the sessionStorage along with the user name on the client side. This is the HTML 5 API used to store data on the client side till the session is active. Once the token is generated, the Employee details is displayed by transferring control to the Index view of the Employee controller.

EmpService.js

//1.
app.service('empservice', function ($http) {
    this.get = function () {
        
        var accesstoken = sessionStorage.getItem('accessToken');
        var authHeaders = {};
        if (accesstoken) {
            authHeaders.Authorization = 'Bearer ' + accesstoken;
        }
        var response = $http({
            url: "/api/EmployeeAPI",
            method: "GET",
            headers: authHeaders
        });
        return response;
    };
});

This is the Angular service. This contains the get () function which reads the access token from the sessionStorage. This token is passed in the request header to the EmployeeAPI service using the Authorization header of the $http. This means that the call to the Web API are secure based on the Token based authentication.

EmployeeController.js

//1.
app.controller('emplcontroller', function ($scope, empservice) {
    $scope.Employees = [];
    $scope.Message = "";
    $scope.userName = sessionStorage.getItem('userName');
    loadEmployees();
    function loadEmployees() {
        
        var promise = empservice.get();
        promise.then(function (resp) {
            $scope.Employees = resp.data;
            $scope.Message = "Call Completed Successfully";
        }, function (err) {
            $scope.Message = "Error!!! " + err.status
        });
    };
    $scope.logout = function () {
         
        sessionStorage.removeItem('accessToken');
        window.location.href = '/Login/SecurityInfo';
    };
});

The above code is for the angular controller. This makes call to the get () function of the empservice. The controller has the loadEmployees () function which displays all employees received when the call is successfully completed. The controller reads the current login user name from the sessionStorage and displays it on View. The logout () function removes the access token from the sessionStorage and the control is transferred to the login page.

Step 3: Open Index.cshtml of the Employees sub-folder of the View folder and add the following markup in it:

<html ng-app="appmodule">
<head>
    <link href="~/Content/bootstrap.min.css" rel="stylesheet" />
head>
<body ng-controller="emplcontroller">
    <h1>Employee Informationh1>
    <h2>
        <span>{{userName}}span>
        <input type="button" class="btn" value="logoff" ng-click="logout()"/>
    h2>
    <table class="table table-striped table-striped table-bordered">
        <thead>
            <tr>
                <th>EmpNoth>
                <th>EmpNameth>
                <th>Salaryth>
                <th>DeptNameth>
            tr>
        thead>
        <tbody>
            <tr ng-repeat="Emp in Employees">
                <td>
                    <span>{{Emp.EmpNo}}span>
                td>
                <td>
                    <span>{{Emp.EmpName}}span>
                td>
                <td>
                    <span>{{Emp.Salary}}span>
                td>
                <td>
                    <span>{{Emp.DeptName}}span>
                td>
            tr>
        tbody>
    table>
    <div><span>{{Message}}span>div>
    <a href="http://~/Scripts/jquery-2.1.4.min.js" rel="nofollow" target="_blank">http://~/Scripts/jquery-2.1.4.min.jsa>
    <a href="http://~/Scripts/bootstrap.min.js" rel="nofollow" target="_blank">http://~/Scripts/bootstrap.min.jsa>
    <a href="http://~/Scripts/angular.min.js" rel="nofollow" target="_blank">http://~/Scripts/angular.min.jsa>
    <a href="http://~/Scripts/MyScripts/Module.js" rel="nofollow" target="_blank">http://~/Scripts/MyScripts/Module.jsa>
    <a href="http://~/Scripts/MyScripts/EmpService.js" rel="nofollow" target="_blank">http://~/Scripts/MyScripts/EmpService.jsa>
    <a href="http://~/Scripts/MyScripts/EmployeeController.js" rel="nofollow" target="_blank">http://~/Scripts/MyScripts/EmployeeController.jsa>
body>
html>

The above markup loads the angular module, EmpService and EmployeeController to display Employees received from the Web API.

Open SecuirtyInfo.cshtml from the Login Sub-folder of the Views folder and add the following markup:

<html ng-app="appmodule">
<head>
    <link href="~/Content/bootstrap.min.css" rel="stylesheet" />
head>
<body ng-controller="logincontroller">
    <h1>The Security Information Viewh1>
    <table class="table table-bordered table-striped table-condensed">
        <tr>
            <td>
                <table class="table table-bordered table-striped table-condensed">
                    <tr>
                        <td>Email:td>
                        <td>
                            <input type="text" class="form-control"
                                  ng-model="userRegistrationEmail" />
                        td>
                    tr>
                    <tr>
                        <td>Password:td>
                        <td>
                            <input type="password" class="form-control"
                                   ng-model="userRegistrationPassword" />
                        td>
                    tr>
                    <tr>
                        <td>Confirm Password:td>
                        <td>
                            <input type="password" class="form-control"
                                   ng-model="userRegistrationConfirmPassword" />
                        td>
                    tr>
                    <tr>
                        <td>td>
                        <td>
                            <input type="button" value="Register"
                                   class="form-control btn btn-success"
                                   ng-click="registerUser()" />
                        td>
                    tr>
                table>
            td>
            <td>td>
            <td>td>
            <td>
                <table class="table table-bordered table-striped table-condensed">
                    <tr>
                        <td>Email:td>
                        <td>
                            <input type="text" class="form-control"
                                   ng-model="userLoginEmail" />
                        td>
                    tr>
                    <tr>
                        <td>Password:td>
                        <td>
                            <input type="password"
                                   class="form-control"
                                   ng-model="userLoginPassword" />
                        td>
                    tr>
                    <tr>
                        <td>td>
                        <td>td>
                    tr>
                    <tr>
                        <td>td>
                        <td>
                            <input type="button" value="Login" class="form-control btn btn-success"
                                   ng-click="login()" />
                        td>
                    tr>
                table>
            td>
        tr>
    table>
    <divdiv>
    <a href="http://~/Scripts/jquery-2.1.4.min.js" rel="nofollow" target="_blank">http://~/Scripts/jquery-2.1.4.min.jsa>
    <a href="http://~/Scripts/bootstrap.min.js" rel="nofollow" target="_blank">http://~/Scripts/bootstrap.min.jsa>
    <a href="http://~/Scripts/angular.min.js" rel="nofollow" target="_blank">http://~/Scripts/angular.min.jsa>
    <a href="http://~/Scripts/MyScripts/Module.js" rel="nofollow" target="_blank">http://~/Scripts/MyScripts/Module.jsa>
    <a href="http://~/Scripts/MyScripts/LoginLogic.js" rel="nofollow" target="_blank">http://~/Scripts/MyScripts/LoginLogic.jsa>
body>
html>

The above markup loads the angular module, LoginLogic JavaScript files. The markup contains data-binding based on the scope defined in the logincontroller.

Running and Execution the Angular.js Application

The Token-Based authentication for Web API in JavaScript client application works as shown in the following diagram:

token-auth-with-web-api

In case of using Token-Based Authentication in Web API, the Web API Controller behaves as a resource server. The client logs in using JavaScript client application and submits the credentials. The client application sends this information to the Web API. In the Web API resources, the Authorization server is responsible for generating the access token. The OWIN Middleware is called by the Authorization server to handle OAuth2, which manages the authorization flow. The generated token is sent back to the client. The client stores the token with it. Henceforth each request made by the client stores the Token in Http header which is handled by the Web API request processing. This processing starts from Authentication filter, which talks to the OWIN Middleware for OAuth. If the token is valid, the request processing finally executes the ApiController and its action method to generate the response with data. This data is sent to the client application.

Run the application, the following Login Page will be displayed where the User Can be registered.

user-registration

Once the user is created, the application will create the database with AspNetUsers table. This will store user credentials in it.

Enter the newly created User Name and Password and click on Login Button, if the credentials are validated then the Employee information will be displayed as shown in the following image

emp-details

To view the Access Token generated, open Developer Tools by pressing F12. In the Console Tab enter sessionStorage and press enter, the details will be displayed as shown in the following image

Click on Logoff button, the user will be log off.

Conclusion:

Token-Based authentication provides additional security for web applications. This is more suitable in case of applications created using JavaScript frameworks and Mobile clients. Web API provides OWIN Middleware APIs using which Token generation and validation is handled.

Source: ItpTechMag

blog.mousavi.fr

Advertisements