Implementing Token-based Authentication in ASP.NET Web API with OAuth and jQuery

In this article, I will guide you through implementing token-based authentication in an ASP.NET Web API project using OAuth and integrating it with jQuery to securely access API endpoints. This builds upon a series of articles Building a RESTful API with ASP.NET Web API and Consuming it Using AJAX where we previously discussed API development and consumption with jQuery.

Setting Up the Database and Data Access Layer:

  • We begin by creating a Users table in SQL Server to store user credentials and roles.

CREATE TABLE Users (
 UserID INT PRIMARY KEY, 
 UserName VARCHAR(50),  
 UserPassword VARCHAR(50), 
UserRoles VARCHAR(500), 
UserEmailID VARCHAR(100),
)
INSERT INTO Users VALUES(1, 'User1', '12345', 'Admin', '[email protected]') 
INSERT INTO Users VALUES(2, 'User2', '12345', 'User', '[email protected]') 
INSERT INTO Users VALUES(3, 'User3', '12345', 'SuperAdmin', '[email protected]') 
INSERT INTO Users VALUES(4, 'User4', '12345', 'Admin, User', '[email protected]')         

  • Create a class library project DataAccessLayer and add class DatabaseTransections inherited from DbContext to manage database interactions via Entity Framework.

public class DatabaseTransections : DbContext
{
    public DatabaseTransections() : base("name=ConStr") { }
    public virtual DbSet<ProductEntity> Product { get; set; }
    public virtual DbSet<UsersEntity> Users { get; set; }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<ProductEntity>().ToTable("tblProduct");
        modelBuilder.Entity<UsersEntity>().ToTable("Users");
    }
}        

Defining Entities and Repositories:

  • Create an entity UsersEntity mirror the database schema for seamless interaction.
  • Create a repository UsersRepository to handles data operations, including user authentication.

public class UsersEntity
{
    [Key]
    public int UserID { get; set; }
    public string UserName { get; set; }
    public string UserPassword { get; set; }
    public string UserRoles { get; set; }
    public string UserEmailID { get; set; }
}
public class UsersRepository
{
    private readonly DatabaseTransections transection;
    public UsersRepository(DatabaseTransections _transection) { transection = _transection; }
    public UsersEntity ValidateUser(string _userName, string _userPassword)
    {
      return transection.Users.FirstOrDefault(user => user.UserName.Equals(_userName, StringComparison.OrdinalIgnoreCase) && user.UserPassword == _userPassword);
    }
}

public class ProductEntity
{
    public int ID { get; set; }
    public string ProductName { get; set; }
    public int UnitPrice { get; set; }
    public int Quantity { get; set; }
}

public class ProductRepository
{
    private readonly DatabaseTransections transection;
    public ProductRepository(DatabaseTransections _transection) 
    { transection = _transection; }

   public List<ProductEntity> GetALLProducts()
   {
      return transection.Product.ToList();
   }
}        
DataAccessLayer - ClassLibrary

Setting Up ASP.NET Web API Project

  • Add ASP.NET Web API (Empty) project.

ASP.NET

  • After creating ASP.NET Web API project add following Libraries

  1. Microsoft.Owin.Host.SystemWeb
  2. Microsoft.Owin.Security.OAuth
  3. Microsoft.Owin.Cors
  4. Newtonsoft.json
  5. Solution Reference (Class Library) DataAccessLayer.

Configuring OAuth Server with OWIN:

  • Add AuthorizationServerProvider class extends OAuthAuthorizationServerProvider to validate client authentication and grant access tokens.

public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
{
    public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        context.Validated();
    }
    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
        UsersRepository _repo = new UsersRepository(new DatabaseTransections());
        var user = _repo.ValidateUser(context.UserName, context.Password);
        if (user == null)
        {
            context.SetError("invalid_grant", "Provided username and password is incorrect");
            return;
        }
        var identity = new ClaimsIdentity(context.Options.AuthenticationType);
        identity.AddClaim(new Claim(ClaimTypes.Role, user.UserRoles));
        identity.AddClaim(new Claim(ClaimTypes.Name, user.UserName));
        identity.AddClaim(new Claim("Email", user.UserEmailID));
        context.Validated(identity);
    }
}        

  • Now navigate to App_Start folder and add class startup.cs.

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
        OAuthAuthorizationServerOptions options = new OAuthAuthorizationServerOptions
        {
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/token"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
            Provider = new AuthorizationServerProvider()
        };
        app.UseOAuthAuthorizationServer(options);
        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
    }
}        

  • In this startup.cs class we mentioned following

  1. Access Token will be accessed using /token URL and token will be expired in 24 hours.
  2. AuthorizationServerProvider will be used to validate the user.
  3. We tell application to use BearAuthorizationOptions as mentioned while generating token.

Creating API Endpoints:

  • Add a controller ProductController exposes APIs to fetch products from the database.
  • Mention Authorize attribute ensures that endpoints are accessed only with valid tokens.

public class ProductController : ApiController
{
    [HttpGet]
    [Authorize]
    public IEnumerable<ProductEntity> GetAllProducts()
    {
        return new ProductRepository(new DatabaseTransections()).GetALLProducts();
    }
}        

Client-side Integration with jQuery:

  • Fetches an access token by making a POST request to the token endpoint /token.
  • On successful token retrieval, the token is stored in session storage.

$("#getToken").click(function ()
{
   $.ajax({
   url: "https://localhost:53078/token",
   method : "POST",
   contentType: "application/json",
   data: {
        username: 'User1',
        password: '12345',
        grant_type: 'password'
   },
   success: function (response) {
       sessionStorage.setItem("access_Token", response.access_token);
   },
   error: function (xhr) {
        alert(xhr.responseText);
   }
  });
});        

  • Fetch all products from database using access token from session storage.

var ulProducts = $("#ulProducts");
$("#loadAllProducts").click(function () {
    $(ulProducts).empty();
    $.ajax({
     type: "GET",
     url: "https://localhost:53078/api/Product",
     datatype: "json",
     headers : {
         "Authorization": "Bearer " + sessionStorage.getItem("access_Token")
     },
     success: function (data) {
        $.each(data, function (index, val) {
        ulProducts.append("<li class=\"list-group-item\"><i class=\"glyphicon glyphicon-trash\" onClick = \"deleteProduct(this," + val.ID + ")\"></i>  " + val.ProductName + "<span class=\"badge rounded-pill\">" + val.Quantity + "</span></li>");
         });
      },
      complete: function (xhr) {
        if (xhr.status == "401")
           ulProducts.append("<li class=\"list-group-item\" style = \"color:red;\"> " + xhr.status + " : " + xhr.statusText + "</li>");
      }
  });
});        

Summary

By implementing token-based authentication:

  • Security: Protects API endpoints from unauthorized access using OAuth tokens.
  • Scalability: Enables secure access to resources while scaling the application.
  • User Experience: Enhances user experience by securely authenticating and authorizing API requests.

This article extends our previous discussion on API development, demonstrating the importance of integrating authentication mechanisms to secure APIs against unauthorized access.

要查看或添加评论,请登录

Zohaib Malik的更多文章

社区洞察

其他会员也浏览了