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
CodePudding user response:
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"));
}
}
}
CodePudding user response:
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;
}