Introduction
Some line of business (LOB) applications or internal systems have predefine 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 Identity framework with persisting roots in entity framework, you have a recipe of headache in your hand. Those frameworks might be useful or desired in certain situation, but here we have a limited scope and in situation likes this we can rather take a lighter approach towards this functionality.
In this post we will see a way to implement authentication functionality in ASP .NET Core Web applications. We will see all the steps and how things are put together to achieve the desired result. The source code is available on this git repository.
Requirements/Considerations
- We’ll need some form of user-store/service where we can store our user’s credentials.
- Sign-in mechanism which will also response with JWT Token.
- JWT wiring in ASP.NET Core and handling
I’ve created a .NET Core Web API project using visual studio project template and this comes with a default controller:
The following picture shows data returned by WeatherForecastController:
Protecting the API with JWT
First, we will need a nuget package to include JWT in ASP.NET Core pipe line:
Next, I’ve updated the startup.cs file to wire-up JWT:
With these changes in place, I created another method in WeatherForecastController and protected it with [Authorize] attribute:
If, we try to call this end-point, it will result in 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
Lets define a User entity and interface of a service called UserService:
Here is our User class and as you can see it is very basic:
Next, we have an interface IUserService as shown below:
UserService Implementation
Let’s implement IUserService interface. As we can recall from introduction, we need some sort of user-store to store credentials. This service will act as a data-store for our application user’s as well:
You can see that I defined a dictionary _users to store credentials information (notice the use of tuple in _users dictionary) and I am populating this dictionary in constructor. Next, lets see how 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, then return the result.
Next we will register UserService with IoC container in startup.cs file.
ASP .NET Core UserService Registration
Please see the image below where I am populating UserName, password in a dictionary, passing it to UserService and then registering UserService as singleton:
So, now where ever in our code, we need to access the UserService, it will be available via Dependency Injection.
Login, Claims & Response
So, we have user-store, a way to validate credentials and now, we need a way to allow users to get JWT tokes by providing their user-name and password. Once this token is received, user or client-applications can include it as Authorization Header to access protected endpoints.
This code is mostly infrastructure code and there are a lot of examples online utilizing similar mechanism for JWT. So, we will start by creating a new controller called AuthController:
We are injecting UserService via DI and we have only one SingIn endpoint which accepts a SignInModel via Http post.
I have added few classes in 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 SignIn method:
Here, we are validating credentials, creating couple of claims and the creating an instance of UserAuth (See class above) and return it to caller.
Before we see the code of TokenUtils.BuildUserAuthObject(), lets see the output of this method. I used PostMan tool to make an HTTP Post to the signin endpoint with UserName and Password:
and this call returns us bearerToken along with some other data. Now we can use this bearerToken to access restricted endpoints. we just need to add it as Authorization header in the HTTP request:
as you can see, this time, data was returned from the protected endpoint. So bearer token is returned when we make call with 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 bearer token is being generated. It is a very boiler-plate code and if something is not clear, feel free to ask in comments:
Hashing Passwords
Our, implementation is finished, however it can be improved. We are currently storing the password in memory and in plain-text. However, if we want, we can store password hash instead.
I added the Bcrypt.Net-Next nuget package to the solution:
Now in UserService constructor, use its HashPassword method as shown below:
We also need to update the verify mechanism for password as shown below:
With, these changes in place, now we have hashed password in memory and its more secure.
Summary
We saw how we can implement in-memory logins for simple applications. Even small, this is a very secure mechanism utilizing JWT and BCrypt nuget packages. You can further extend by connecting it with database persistence or adding more capabilities to 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 question. feel free to ask. Till next time, happy coding.
My Recent Books
Discover more from Hex Quote
Subscribe to get the latest posts sent to your email.