Basic Authentication with ASP.Net Core Web API Using MySQL Server
Introduction
In this tutorial we'll go
through how to implement Basic HTTP authentication in a
.NET 3.1 API with C#.
API has just two
endpoints/routes to demonstrate authenticating with basic http authentication
and accessing a restricted route:
- /users/authenticate - public
route that accepts HTTP POST requests containing the username and password
in the body. If the username and password are correct then the user
details are returned.
- /users - secure route that
accepts HTTP GET requests and returns a list of all the users in the
application if the HTTP Authorization header contains valid basic
authentication credentials. If there are no basic auth credentials or the
credentials are invalid then a 401 Unauthorized response is returned.
Prerequisites
- .NET 3.1
- Visual Studio 2019
1. 1. Open Visual Studio 2019 and create a new project.
2. Select the
“Asp.Net Core Web API” template and click on Next.
3. Provide Project name and location.
4. Select Target Framework and click on Create button.
5.
Once project is create basic view in solution
explore.
6. Once project is create basic view in solution explore.
7.
Need to install dependency from Genet packages.
MySql.Data.dll
Microsoft.AspNetCore.Mvc.NewtonsoftJson.dll
– version 3.1.10
Azure.Storage.Blobs –
version 12.1.0
8.
Please add below code’s of lines in startup.cs
services.AddAuthentication("BasicAuthentication")
.AddScheme<AuthenticationSchemeOptions,
BasicAuthenticationHandler>("BasicAuthentication", null);
services.AddScoped<IUserService,
UserService>();
9.
Next we need to create UsersController.cs and add below code in
controller class.
The controller actions are secured with basic authentication using the [Authorize] attribute,
with the exception of the Authenticate method which allows
public access by overriding the [Authorize] attribute on the
controller with the [AllowAnonymous] attribute on the action
method.
Path: /Controllers/UsersController.cs
using System;
using
System.Collections.Generic;
using
System.Data;
using
System.Linq;
using
System.Threading.Tasks;
using
CEEAWebAPI.Models;
using
Microsoft.AspNetCore.Authorization;
using
Microsoft.AspNetCore.Http;
using
Microsoft.AspNetCore.Mvc;
using
Microsoft.Extensions.Configuration;
using
MySql.Data.MySqlClient;
namespace CEEAWebAPI.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class UsersController : ControllerBase
{
private IUserService _userService;
private readonly IConfiguration _configuration;
//private readonly
IConfiguration _configuration;
public UsersController(IUserService userService, IConfiguration configuration)
{
_userService = userService;
_configuration = configuration;
}
//[AllowAnonymous]
[HttpPost("authenticate")]
public async
Task<IActionResult> Authenticate([FromBody] User userParam)
{
var user = await
_userService.Authenticate(userParam.Username, userParam.Password);
if (user == null)
return BadRequest(new {
message = "Username or password is incorrect" });
return Ok(user);
}
[HttpGet]
public async
Task<IActionResult> GetAll()
{
var users = await _userService.GetAll();
//var GetUser =
Getproducts();
return Ok(users);
}
10.
Next create User.cs to get and set fields
The user entity class represents the data for
a user in the application. Entity classes are used to pass data between
different parts of the application.
Path: /Modules
/User.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace CEEAWebAPI.Models
{
public class User
{
public int UserId {
get; set; }
public string
FirstName { get; set; }
public string LastName
{ get; set; }
public string Username
{ get; set; }
public string Password
{ get; set; }
public string EmailId
{ get; set; }
}
}
11.
Basic
Authentication Handler.
Path: / Modules /BasicAuthenticationHandler.cs
The basic authentication handler
is .NET middleware that handles request authentication by inheriting from the
.NET AuthenticationHandler base class and overriding the HandleAuthenticateAsync() method.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using CEEAWebAPI.Models;
namespace CEEAWebAPI.Models
{
public class BasicAuthenticationHandler :
AuthenticationHandler<AuthenticationSchemeOptions>
{
private readonly IUserService _userService;
public BasicAuthenticationHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock,
IUserService userService)
: base(options, logger, encoder, clock)
{
_userService = userService;
}
protected override async
Task<AuthenticateResult> HandleAuthenticateAsync()
{
if(!Request.Headers.ContainsKey("Authorization"))
return AuthenticateResult.Fail("Missing
Authorization Header");
User user = null;
try
{
var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' }, 2);
var username = credentials[0];
var password = credentials[1];
user = await _userService.Authenticate(username,
password);
}
catch
{
return AuthenticateResult.Fail("Invalid
Authorization Header");
}
if (user == null)
return AuthenticateResult.Fail("Invalid
Username or Password");
var claims = new[] {
new Claim(ClaimTypes.NameIdentifier, user.UserId.ToString()),
new Claim(ClaimTypes.Name, user.Username),
};
var identity = new
ClaimsIdentity(claims, Scheme.Name);
var principal = new
ClaimsPrincipal(identity);
var ticket = new
AuthenticationTicket(principal, Scheme.Name);
return AuthenticateResult.Success(ticket);
//throw new
NotImplementedException();
}
}
}
12. User Service
Path: / Modules /UserService.cs
The user service contains a method for authenticating user credentials,
and a method for getting all users in the application.
The top of the file contains an interface that defines the
user service, below that is the concrete user service class that
implements the interface.
On successful authentication the Authenticate method returns
the user details, the client application should then include the base64 encoded
user credentials in the HTTP Authorization header of subsequent api requests to
access secure endpoints.
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using MySql.Data.MySqlClient;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace CEEAWebAPI.Models
{
public interface IUserService
{
Task<User> Authenticate(string username, string password);
Task<IEnumerable<User>>
GetAll();
}
public class UserService : IUserService
{
private readonly IConfiguration _configuration;
public UserService(IConfiguration configuration)
{
_configuration = configuration;
}
List<User> _users = new List<User>();
//private
List<User> _users = new List<User>
//{
// new User { UserId = "1",
FirstName = "Test", LastName = "User", Username =
"test1", Password = "test1" }
// //var a = new Getproducts();
// };
public async
Task<User> Authenticate(string username, string
password)
{
GetUserTable();
var genpassword= GenerateMySQLHash(password);
var user = await
Task.Run(() => _users.SingleOrDefault(x => x.Username == username
&& x.Password == genpassword));
// return null
if user not found
if (user == null)
return null;
//
authentication successful so return user details without password
user.Password = null;
return user;
}
public async
Task<IEnumerable<User>> GetAll()
{
GetUserTable();
//return users
without passwords
return await
Task.Run(() => _users.Select(x =>
{
x.Password = null;
return x;
}));
}
// Getting data
from user tabel from database
private List<User> GetUserTable()
{
string query = @"select * from
restapi.user;";
DataTable table = new DataTable();
string sqlDataSource = _configuration.GetConnectionString("EmployeeAppcon");
MySqlDataReader myReader;
using (MySqlConnection mycon = new MySqlConnection(sqlDataSource))
{
mycon.Open();
using (MySqlCommand mycommond = new MySqlCommand(query, mycon))
{
myReader =
mycommond.ExecuteReader();
table.Load(myReader);
myReader.Close();
mycon.Close();
}
}
for (int i = 0; i
< table.Rows.Count; i++)
{
User usr = new User();
usr.UserId =
Convert.ToInt32(table.Rows[i]["userid"]);
//usr.UserId
= table.Rows[i]["userid"].ToString();
usr.Username = table.Rows[i]["userName"].ToString();
usr.Password = table.Rows[i]["password"].ToString();
usr.FirstName = table.Rows[i]["firstName"].ToString();
usr.LastName = table.Rows[i]["lastName"].ToString();
usr.EmailId = table.Rows[i]["emailid"].ToString();
_users.Add(usr);
}
return (_users);
}
// password
converstion to Hash key
public string GenerateMySQLHash(string key)
{
byte[] keyArray = Encoding.UTF8.GetBytes(key);
SHA1Managed enc = new SHA1Managed();
byte[] encodedKey = enc.ComputeHash(enc.ComputeHash(keyArray));
StringBuilder myBuilder = new StringBuilder(encodedKey.Length);
foreach (byte b in encodedKey)
myBuilder.Append(b.ToString("X2"));
return "*" + myBuilder.ToString();
}
}
}
Comments
Post a Comment