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:
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]')
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:
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();
}
}
Setting Up ASP.NET Web API Project
Configuring OAuth Server with OWIN:
领英推荐
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);
}
}
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());
}
}
Creating API Endpoints:
public class ProductController : ApiController
{
[HttpGet]
[Authorize]
public IEnumerable<ProductEntity> GetAllProducts()
{
return new ProductRepository(new DatabaseTransections()).GetALLProducts();
}
}
Client-side Integration with jQuery:
$("#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);
}
});
});
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:
This article extends our previous discussion on API development, demonstrating the importance of integrating authentication mechanisms to secure APIs against unauthorized access.