3

In ASP.NET Core-6 Web API, this Basic Auth code to be used as an header for my POST, PUT and Get Requests:

--header 'Authorization: Basic GGATEIIIFFFF12234JJKKKKKFFFFFFFFFFFFFF'

In my appsettings.Json, I have the credential as shown below:

  "BasicCredentials": {
    "username": "Akwetey",
    "password": "#12345677**87" //Basic Auth
  },

Then I have this Get Request:

public IEnumerable<Employee> GetEmployees()
{
    List<Employee> employeelist = new List<Employee>();
    using (con = new SqlConnection(connection))
    {
        con.Open();
        command = new SqlCommand("sp_employees", con);
        command.CommandType = CommandType.StoredProcedure;
        dataReader = command.ExecuteReader();
        while (dataReader.Read())
        {
            Employee employee = new Employee();
            employee.EmployeeId = Convert.ToInt32(dataReader["EmployeeId"]);
            employee.Firstname = dataReader["Firstname"].ToString();
            employee.Lastname = dataReader["Lastname"].ToString();
            employee.Email = dataReader["Email"].ToString();
      employee.EmploymentDate = Convert.ToDateTime(dataReader["EmploymentDate"].ToString());

            employeelist.Add(employee);
        }
        con.Close();
    }
    return employeelist;
}

How do I authorise the Get Get Request code above using the Basic Auth Credentials as the header?

Thanks

1
  • @DimitrisMaragkos - What I mean is that the Username and Password are in the appsettings, but how to call it from there and implement it as Basic Auth, to implement the requests Commented Oct 8, 2022 at 21:35

2 Answers 2

5

This is the BasicAuthenticationHandler implementation from dotnetthoughts modified to read the credentials from appsettings.json using IConfiguration:

public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
    private readonly IConfiguration _configuration;

    public BasicAuthenticationHandler(
        IOptionsMonitor<AuthenticationSchemeOptions> options,
        ILoggerFactory logger,
        UrlEncoder encoder,
        ISystemClock clock,
        IConfiguration configuration) : base(options, logger, encoder, clock)
    {
        _configuration = configuration;
    }

    protected override Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        var authHeader = Request.Headers["Authorization"].ToString();

        if (authHeader != null && authHeader.StartsWith("basic", StringComparison.OrdinalIgnoreCase))
        {
            var token = authHeader.Substring("Basic ".Length).Trim();
            Console.WriteLine(token);
            var credentialstring = Encoding.UTF8.GetString(Convert.FromBase64String(token));
            var credentials = credentialstring.Split(':');

            var username = _configuration["BasicCredentials:username"];
            var password = _configuration["BasicCredentials:password"];

            if (credentials[0] == username && credentials[1] == password)
            {
                var claims = new[] { new Claim("name", credentials[0]), new Claim(ClaimTypes.Role, "Admin") };
                var identity = new ClaimsIdentity(claims, "Basic");
                var claimsPrincipal = new ClaimsPrincipal(identity);

                return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(claimsPrincipal, Scheme.Name)));
            }

            Response.StatusCode = 401;
            Response.Headers.Add("WWW-Authenticate", "Basic realm=\"dotnetthoughts.net\"");

            return Task.FromResult(AuthenticateResult.Fail("Invalid Authorization Header"));
        }
        else
        {
            Response.StatusCode = 401;
            Response.Headers.Add("WWW-Authenticate", "Basic realm=\"dotnetthoughts.net\"");

            return Task.FromResult(AuthenticateResult.Fail("Invalid Authorization Header"));
        }
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. But sorry if I'm sounding somehow. How do I now call it in public IEnumerable<Employee> GetEmployees(), so that it will generates and authorize. Thanks
2

You would need to add something along these lines

builder.Services.AddAuthentication()
    .AddScheme<MyAuthenticationOptions, MyAuthenticationHandler>(MyAuthenticationSchemeName, options => {});

Where:

public class MyAuthenticationOptions : AuthenticationSchemeOptions
    {}

and

public class MyAuthenticationHandler : AuthenticationHandler<MyAuthenticationOptions>
    {

        private IConfiguration Configuration;
        public MyAuthenticationHandler(
            IOptionsMonitor<MyAuthenticationOptions> options,
            ILoggerFactory logger,
            UrlEncoder encoder,
            ISystemClock clock,
            IConfiguration configuration
        ) : base(options, logger, encoder, clock)
        {
            Configuration = configuration;
        }

        protected async override Task<AuthenticateResult> HandleAuthenticateAsync()
        {
            // Get the header
            string authHeader = Request.Headers[HeaderNames.Authorization];
            // Parse config this way
            var pwd = Configuration.GetValue<string>("BasicCredentials:password")
            // Check if the header is valid comparing to your config
            // Create here your claims principal
            ClaimsPrincipal principal;
            //...//
            var ticket = new AuthenticationTicket(principal, Scheme.Name);
            return AuthenticateResult.Success(ticket);

            // Or otherwise
            return AuthenticateResult.Fail("Invalid secret.");
        }
    }

Then finally, you can have an authed controller like this

[Authorize]
[HttpGet("employees")]
public IEnumerable<Employee> GetEmployees()
{
    List<Employee> employeelist = new List<Employee>();
    using (con = new SqlConnection(connection))
    {
        con.Open();
        command = new SqlCommand("sp_employees", con);
        command.CommandType = CommandType.StoredProcedure;
        dataReader = command.ExecuteReader();
        while (dataReader.Read())
        {
            Employee employee = new Employee();
            employee.EmployeeId = Convert.ToInt32(dataReader["EmployeeId"]);
            employee.Firstname = dataReader["Firstname"].ToString();
            employee.Lastname = dataReader["Lastname"].ToString();
            employee.Email = dataReader["Email"].ToString();
      employee.EmploymentDate = Convert.ToDateTime(dataReader["EmploymentDate"].ToString());

            employeelist.Add(employee);
        }
        con.Close();
    }
    return employeelist;
}

5 Comments

Kindly allow me ask these questions: 1. Where do I put builder.Services.AddAuthentication() .AddScheme<MyAuthenticationOptions, MyAuthenticationHandler>(MyAuthenticationSchemeName, options => {});
2. and also public class MyAuthenticationOptions : AuthenticationSchemeOptions Is this an interface?
- Where did you call protected async override Task<AuthenticateResult> HandleAuthenticateAsync() in public IEnumerable<Employee> GetEmployees()
1. That would be on your Program.cs or wherever you have you ApplicationBuilder. 2. You will find that in Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions, it is a class 3. You do not have to call it. As soon as you have the aforementioned setup, you add appBuilder.UseAuthentication(); appBuilder.UseAuthorization(); and the [Authorize] annotation on your controller it gets called automatically. Note that your controller class should be inheriting ControllerBase.
As @DimitrisMaragkos mentioned, dotnetthoughts is a very good starter's guide. The last snippet of code that includes [Authorize] is how the handler is being called.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.