In this tutorial we'll go through a simple example of how to implement Basic authentication in ASP.NET Core 2.2 API with C#. I am using Visual Studio 2017 with .Net Core 2.2
for developing the API, and postman tool for testing the API.
First create a new project from Visual Studio 2017(you can also use Visual Studio Code with .Net Core CLI to create sample project structure) with project template
ASP.Net Core Web Application
.
In the next dialog, it will ask you for the default template to auto-generate required project structure for you, here select the API
from given templates.
It will auto-generate a controller ValuesController
with different REST action methods.
Run the project, and from postman make a call to the values controller's get method (you may have a different port number):
https://localhost:44365/api/values
You will see the output:
Till now, we have created a fresh API project and run it successfully. Lets add Basic Authentication in this API.
In Startup.cs, replace the code for ConfigureServices()
method with the following:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
// configure basic authentication
services.AddAuthentication("BasicAuthentication")
.AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>("BasicAuthentication", null);
}
Here we have added BasicAuthenticationHandler
as authentication mechanism for incoming requests. You have to add a using statement:
using Microsoft.AspNetCore.Authentication;
Next, we have to add the class BasicAuthenticationHandler
.
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
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;
namespace CoreApiAuthentication
{
public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
public BasicAuthenticationHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock
)
: base(options, logger, encoder, clock)
{
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!Request.Headers.ContainsKey("Authorization"))
return AuthenticateResult.Fail("Missing Authorization Header");
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];
bool result = await Task.Run(() => IsAuthentic(username, password));
if (result == false)
{
return AuthenticateResult.Fail("Invalid Username or Password");
}
}
catch
{
return AuthenticateResult.Fail("Invalid Authorization Header");
}
var claims = new List<Claim>() {
new Claim(ClaimTypes.NameIdentifier, "test"),
new Claim(ClaimTypes.Name, "test")
};
var identity = new ClaimsIdentity(claims, Scheme.Name);
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, Scheme.Name);
return AuthenticateResult.Success(ticket);
}
private bool IsAuthentic(string usreName, string password)
{
//in real project, authenticate username and password from an external service or database etc.
if ( usreName == "test" && password == "12345")
{
return true;
}
return false;
}
}
}
HandleAuthenticateAsync()
is the method which will be automatically called by the API. Actual authentication logic is being written in the method
IsAuthentic()
, which is checking for a hardcoded username and password, of-course this is only for demo purpose and you will never use
this sort of thing in production code. We are returning AuthenticateResult.Fail()
method call when the authentication is failed
and AuthenticateResult.Success()
method call for successfull authentication.
Next, in Configure()
method you have to tell IApplicationBuilder
object to use authentication.
app.UseAuthentication();
Complete code for this method looks similar to this:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseAuthentication();
app.UseHttpsRedirection();
app.UseMvc();
}
Final thing is to decorate the desired controller(in our case ValuesController
) with Authorize
attribute.
Your API is ready with Basic Authentication. With postman if you make a call without Authorization
header it will give you 401 error.
In our case, valid Authorization
header value (base64 string for our username and password, separated by colon ':') will be:
Basic dGVzdDoxMjM0NQ==
With valid Authorization header postman will receive success response.