16

How to Add Basic Authentication to an ASP.NET Core Application

 3 years ago
source link: https://www.roundthecode.com/dotnet/how-to-add-basic-authentication-to-asp-net-core-application
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Adding Basic Authentication to an ASP.NET Core application is relatively straight forward to do.

Basic Authentication can be used as security when generating an OAuth bearer token.

In addition, it can be used to restrict access to staging websites. This is so search engines cannot accidently crawl a staging website.

We are going to have a look at how Basic Authentication works, and how we can go about setting it up in an ASP.NET Core application.

How does Basic Authentication Work?

Basic Authentication works by adding an Authorization header into a HTTP request.

The value of the Authorization header must be Basic, followed by a space, followed by the username and password separated by a colon. The username and password are encoded using Base64.

For example, if the username is roundthecode and the password is roundthecode, the username and password would be presented like this:

roundthecode:roundthecode

Using Base64 encoding, this would encode the value into the following:

cm91bmR0aGVjb2RlOnJvdW5kdGhlY29kZQ==

So, the full value of the HTTP request Authorization header would be as follows:

Basic cm91bmR0aGVjb2RlOnJvdW5kdGhlY29kZQ==

We can use the Base64 Encode and Decode website to test this out.

How to Setup Basic Authentication in a ASP.NET Core Application?

Now that we have an understanding of how Basic Authentication works, we are going to go ahead and set it up in an ASP.NET Core application.

BasicAuthorization Attribute

The first thing we need to do is to create a BasicAuthorization attribute.

This attribute will be designed to be used in an MVC controller. We can wrap it around a particular action, or wrap it around a whole controller.

The attribute will inherit the AuthorizeAttribute class. When we create an instance of this attribute, we need to be able to set up a policy name. This is something we will have a look at later on.

// BasicAuthorizationAttribute.cs
public class BasicAuthorizationAttribute : AuthorizeAttribute
{
public BasicAuthorizationAttribute()
{
Policy = "BasicAuthentication";
}
}

AuthenticatedUser Class

Next, we want to create an AuthenticatedUser class. This will allow us to determine the identity of the user that has been authenticated.

The AuthenticatedUser class needs to inherit the IIdentity interface. As a result, we need to include three properties in our AuthenticatedUser class.

We need to set the authentication type, whether the user has been authenticated and the user's name.

// AuthenticatedUser.cs
public class AuthenticatedUser : IIdentity
{
public AuthenticatedUser(string authenticationType, bool isAuthenticated, string name)
{
AuthenticationType = authenticationType;
IsAuthenticated = isAuthenticated;
Name = name;
}
public string AuthenticationType { get; }
public bool IsAuthenticated { get;}
public string Name { get; }
}

BasicAuthenticationHandler Class

The final thing we need to build is the BasicAuthenticationHandler class.

This is where we need to build the functionality as to allow the user to be authenticated or not.

The first thing we need to do is to check if there is a Authorization header present in the request headers.

Assuming there is, we need to check if it's been formatted properly. As discussed earlier, the Authorization header value must start with the word "Basic" followed by a space. This is then followed by a Base 64 encoding of the username and password.

Once we have got through that step, we can go ahead and decode the Base 64 string. This will then give us our username and password seperated by a colon.

It's worth noting that the username cannot have a colon, but the password can. This is because our code only splits the first colon and ignores any subsequent colons.

Assuming we are happy with the username and password, we can go ahead and create our user. Afterwards, we add that user to our claims principal which we pass as part of our successful authentication result.

// BasicAuthenticationHandler.cs
public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
public BasicAuthenticationHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock
)
: base(options, logger, encoder, clock)
{
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
Response.Headers.Add("WWW-Authenticate", "Basic");
if (!Request.Headers.ContainsKey("Authorization"))
{
return Task.FromResult(AuthenticateResult.Fail("Authorization header missing."));
}
// Get authorization key
var authorizationHeader = Request.Headers["Authorization"].ToString();
var authHeaderRegex = new Regex(@"Basic (.*)");
if (!authHeaderRegex.IsMatch(authorizationHeader))
{
return Task.FromResult(AuthenticateResult.Fail("Authorization code not formatted properly."));
}
var authBase64 = Encoding.UTF8.GetString(Convert.FromBase64String(authHeaderRegex.Replace(authorizationHeader, "$1")));
var authSplit = authBase64.Split(Convert.ToChar(":"), 2);
var authUsername = authSplit[0];
var authPassword = authSplit.Length > 1 ? authSplit[1] : throw new Exception("Unable to get password");
if (authUsername != "roundthecode" || authPassword != "roundthecode")
{
return Task.FromResult(AuthenticateResult.Fail("The username or password is not correct."));
}
var authenticatedUser = new AuthenticatedUser("BasicAuthentication", true, "roundthecode");
var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(authenticatedUser));
return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(claimsPrincipal, Scheme.Name)));
}
}

How to Configure Basic Authentication in ASP.NET Core

Now that we have the functionality created, it's time to configure our ASP.NET Core application so we can get Basic Authentication to work.

To do this, we need to make two changes in the Startup class.

Add Authentication Scheme

The first thing we need to do is to add the authentication scheme. To do this, we can add the scheme to the AuthenticationBuilder instance inside the ConfigureServices method.

The AddScheme method is what we use. This method allows us to add our BasicAuthenticationHandler as a generic method. As a result, we can hook this scheme against this handler.

In addition, we need to give the scheme a name. In this instance, we are going to call it BasicAuthentication.

// Startup.cs
public class Startup
{
...
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
...
services
.AddAuthentication()
.AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>("BasicAuthentication", options => { });
}
...
}

Add Authorisation Policy

The other thing we need to do is to add an authorisation policy.

Now, when we created the BasicAuthorization attribute, we set a policy name of BasicAuthentication.

We need to make sure that when we add the policy, we give it the same name.

In addition, we need to make sure that for this policy to succeed, we need to have a authenticated user.

public class Startup
{
...
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddAuthorization(options =>
{
options.AddPolicy("BasicAuthentication", new AuthorizationPolicyBuilder("BasicAuthentication").RequireAuthenticatedUser().Build());
});                      
}
...
}

Does the Basic Authentication Work When We Apply It?

Watch the video below to apply Basic authentication to an ASP.NET Core MVC application.

We use the [BasicAuthorization] attribute in an action from one of our controllers.

From there, we go ahead and test the functionality.

Using Basic Authentication When Generating an OAuth Bearer Token

We can use basic authentication when generating a JWT as an OAuth Bearer token.

This gives us some extra security when generating valid Bearer token when using OAuth security.

This is particularly useful for API's. Find out in Part 2 how to implement this which will be available on 23rd December.

Want More ASP.NET Core Coding Tutorials?

Subscribe to my YouTube channel to get more ASP.NET Core coding tutorials.

You'll get videos where I share my screen and implement a how-to guide on a topic related to ASP.NET Core.

You can expect to see videos from the following technologies:

  • Blazor
  • Web APIs
  • SQL Server
  • Entity Framework
  • SignalR
  • and many more...

By subscribing, you can get access to all my ASP.NET Core coding tutorials completely free!

And so you never miss out on a new video, you have the option to be notified every time a new video is published.

So what are you waiting for?

To subscribe, click here to view my YouTube channel, and click on the red "Subscribe" button.

Sign up for the Round The Code Newsletter

Coming soon, we will sending out a newsletter with the latest updates.

Just simply fill out your email below.

Email

Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK