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

  1. .NET 3.1
  2. 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

Popular posts from this blog

Create Data Package file to Import Or Export CRM records.

Receive Incoming Message in Twilio using Power Automate

Azure Function to Read Incoming Message in Twilio

Open canvas app with Customize the command bar using command designer

Execute CRUD operations within the Power Platform using a Canvas App