d

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore.

15 St Margarets, NY 10033
(+381) 11 123 4567
ouroffice@aware.com

 

KMF

In-Memory Logins in ASP.NET Core with JWT

Introduction

Some line of business (LOB) applications or internal systems have a predefined set of users and corresponding login information. In situations like those, using a database mechanism to store user information is an overhead. Combine this overhead with Microsoft’s heavy-duty implementation of the Identity framework with persisting concerns in the Entity framework, and you have a recipe for a headache. Those frameworks might be useful in certain situations, but here we have a limited scope and, in situations like this, we can, instead, take a lighter approach towards this functionality.

In this post, we will look at a way to implement authentication functionality in an ASP.NET Core Web application. We will go through all the steps and how things are put together to achieve the desired result. The source code is available in this GitHub repository.

Requirements/Considerations

We’ll need: 

  • Some form of a user-store/service where we can store our user’s credentials.
  • A sign-in mechanism, which will also respond with JSON Web Tokens (JWTs).
  • JWT wiring in ASP.NET Core and handling.

I’ve created a .NET Core Web API project using a Visual Studio project template and this comes with a default controller:

The following picture shows data returned by WeatherForecastController:

Protecting the API With JWTs

First, we will need a Nuget package to include JWTs in our ASP.NET Core pipeline:

Next, I’ve updated the startup.cs file to wire-up a JWT:

With these changes in place, I created another method in WeatherForecastController and protected it with the [Authorize] attribute: 

If we try to call this end-point, it will result in a 401 Unauthorized error as shown below:

So, this confirms that our end-point is now protected from unauthorized access.

Let’s continue and see how we can allow certain users access to protected endpoints.

User Entity and UserService Interface

Let’s define a User entity and interface for a service called UserService:

Here is our User class. As you can see, it is very basic:

Next, we created an interface named IUserService as shown below:

UserService Implementation

Let’s implement the IUserService interface. As we can recall from the introduction, we need some sort of user-store to store credentials. This service will act as a data-store for our application’s users as well:

You can see that I defined a dictionary with _users to store credentials (notice the use of a tuple in the _users dictionary) and I am populating this dictionary via the constructor. Next, let’s see how the ValidateCredentials method is implemented:

I think the code is very simple to follow. We are just finding the user in the dictionary, checking the password, and, if everything is ok, returning the result.

Next, we will register UserService with an IoC container in the startup.cs file.

ASP.NET Core UserService Registration

Please see the image below where I am populating UserName with passwords in a dictionary, passing it to UserService, and then registering UserService as singleton:

So, now wherever in our code we need to access the UserService, it will be available via Dependency Injection.

Login, Claims, and Response

So, we have a user-store, a way to validate credentials, and, now, we need a way to allow users to get JWTs by providing their user name and password. Once this token is received, users or client applications can include it as an Authorization Header to access protected endpoints.

This code is mostly infrastructure code, and there are a lot of examples online that utilize a similar mechanism for JWTs. So, we will start by creating a new controller called AuthController:

We are injecting UserService via dependency injection, and we have only one SingIn endpoint, which accepts a SignInModel via HTTP POST.

I have added a few classes to the project. These classes are used as a data-bag to move data around, and we will see how those are being used in a moment:

Let’s see the code for the SignIn method:

Here, we are validating credentials, creating a couple of claims, creating an instance of UserAuth (see class above), and returning it to the caller.

Before we check out the code for TokenUtils.BuildUserAuthObject(), let’s see the output of this method. I used Postman to make an HTTP POST to the signin endpoint with UserName and Password:

This call returns bearerToken along with some other data. Now we can use this bearerToken to access restricted endpoints. We just need to add it as an Authorization header in the HTTP request: 

As you can see, this time, data was returned from the protected endpoint. So a bearer token is returned when we make a call with a valid username and password, and then we use that bearer token with other HTTP requests to access protected data.

Token Generation

Now, let’s see how the bearer token is being generated. It is very boiler-plate code, and if something is not clear, feel free to ask in the comments:

Hashing Passwords

Our implementation is finished, but it can be improved. We are currently storing the password in memory and in plain-text. However, if we want, we can store the password hash instead.

I added the Bcrypt.Net-Next nuget package to the solution:

Now in the UserService constructor, use its HashPassword method as shown below:

We also need to update the verify mechanism for the password as shown below:

With these changes in place, we have a hashed password in memory, and it’s more secure.

Summary

We saw how we can implement in-memory logins for simple applications. Even small, this is a very secure mechanism utilizing JWTs and BCrypt nuget packages. You can further extend it by connecting it with database persistence or adding more capabilities to the in-memory store, e.g. Registering New Users can be done easily.

You can download the source code from this git repository. If you have some comments or questions, feel free to ask. Till next time, happy coding.

Credit: Source link

Previous Next
Close
Test Caption
Test Description goes like this