In this next part of the Blazor Blog Series, Let’s learn about implementing Custom Authentication in Blazor WebAssembly Project (Blazor.Learner). We will cover some core concepts that can get you familiar with how authentication works in Blazor Applications.
PS, This is quite a detailed Article with around 3000 words. So I suggest you to bookmark this page for future reference. Grab a drink and let’s get started!
Built-in Authentication
Microsoft Ships Blazor with Built-in Authentication that can get you started quickly. But this is not what we will be looking into today. The Built-in Approach has quite a lot of limitations. For instance, what if you already have a Blazor project and want to implement authentication? You would not be able to do so. However, here is how you can set up the out-of-the-box Authentication in Blazor WebAssembly.
The other limitations of the built-in authentication in Blazor are as follows.
-
You will always have to use the Entity Framework Core - Code First Approach. This is not ideal for most developers.
-
This uses the old Razor Pages, not the new Razor components.
-
If you already have a database with existing users, it might be really tough to integrate this authentication.
That is why we have Custom Authentication in Blazor. Let’s begin.
Implementing Custom Authentication in Blazor WebAssembly
We will start off from where we left off in our previous Part - Blazor CRUD with Entity Framework Core – Detailed Tutorial. You can get the source code here. (blazor-blog-series-part-3 branch)
PS, The provided GitHub link takes you to the repository branch where we left off. The master is the current branch.
Login & Register Models
As usual, we need to build the model classes that would take in various authentication parameters for login and registering new users. We will create these classes in the Shared Project under the Models folder. You will need to install a package to help us with the Data Annotations. (Validations for the Models)
Let’s add the Register Model, Models/RegisterRequest.cs
Now create a model for Login, Models/LoginRequest.cs
Finally, we will need one mode model in the Share Project that is going to hold the details of the current user. Models/CurrentUser.cs
That’s all to do in the Shared Project. Now we have classes to help hold authentication parameters. In this tutorial, we will go by using Microsoft Identity. You could switch this with your own logic if needed. Let’s a mode for our User. Since this Model will inherit from IdentityUser, we will be adding it to the Server Project. But before that, let’s add the required packages to our Server Project. PS, you may want to update all your existing packages before installing new ones.
Now in the Server Project, add a new class at Models/ApplicationUser.cs
Let’s modify our ApplicationDbContext class to support identity. Navigate to Data/ApplicationDBContext.cs and make the following changes.
After that, navigate to Server/Startup.cs and make the following changes.
We will be using Cookies for state management. You could use Session Storage as well. Do not forget to add Authentication and Authorization Middlewares to the application. Navigate to the Configure method of Startup.cs and add these lines below app.UseRouting();
Make sure that you add these lines in the same order. With that done, we can proceed to migrations and updating the database, so that we create the required Identity tabes.
The only thing that is left to do in Server Project is to actually add the API endpoint to log in, register, log out, and get current user details. Let’s add a new Controller for this at Controllers/AuthController.cs
Line #1 - For accessing the endpoints like ..api/auth/login or …api/auth/register
Line #5-11 Constructor Injection of the Identity Interfaces for signing in and creating new users etc.
No, we will add the required Action Methods. Note that these are all very basic methods. You could probably implement your logic here if needed to match your business requirement.
Login - Controller Method
Register - Controller Method
Here we are also returning a Login Model after a successful registration. This is to implement auto-login after the user registers.
Logout - Controller Method
Get Current User - Controller Method
Returns the currently logged-in user with an authentication state. We will also fetch the claims that can possibly contain the Roles as well. With this, we can say that the coding needed in the Server Project is done. The only aim of the server project is to provide the data. We have built the Auth Endpoint that GETS or POSTS data from/to the Datasource.
Now, The Main Part - Authentication in Blazor WebAssembly
Firstly, there is one package that is needed to be installed on the Client Project. Let’s install it.
As mentioned previously, we now have api endpoints to facilitate authentication stuff. Now the only task left for us is to utilize these endpoints in our Client Project, right? As usual, to access endpoints, let’s add a service and its interface. We will name them AuthService and IAuthService. So the idea is that we will access these api endpoints by using an instance of injected HTTP Client in the service class from our Client Project.
Add a new interface to the client project. Services/IAuthService.cs
Authentication State Provider
As the name suggests, this class provides the state of authentication of the user in Blazor Applications. AuthenticationStateProvider is an abstract class in the Authorization namespace. Blazor uses this class which would be inherited and overridden by us with custom implementation for getting the user state. This state can be from either local storage, session storage, or cookies like in our case.
Let’s start by adding the Provider class in the Services folder. Let’s name it CustomStateProvider. As mentioned, this class will inherit the AuthenticationStateProvider class.
You can see that, by default we get to implement a function GetAuthenticationStateAsync. Now this function is quite important as Blazor calls this very often to check the state of authentication of the user in the application. Get the point?
Also, we will be injecting the AuthService and the CurrentUser Model into the constructor of this class. The idea behind this is that we will not be directly using the service instance in the view (Razor Components), rather we will inject the instance of CustomStateProvider into our views that would in turn access the services.
Here is the finished State Provider class. I will explain it in a bit.
GetAuthenticationStateAsync - Get the current user from the service object. if the user is authenticated, we will add his/her claims to a list and create and Claims Identity. After this, we will return an Authentication State with the required data.
The other 3 Methods are pretty straightforward. We will just be calling the required service methods. But here is one extra thing that I would want to explain. Now with every log in, registration, and logout, technically there is a state change in the authentication. We need to let the entire application know that the user’s state has changed. Hence we use a Notify Method and pass the current authentication state by calling the GetAuthenticationStateAsync. Pretty logical, yeah?
Now, to activate these services and dependencies in the Client Project, we need to register them into the container yeah? For this, Navigate to the client project’s Program.cs and make the following additions.
That’s done too! Now let’s work on adding the Razor Components for the UI. Here we will have to add 2 Components, i.e., the Login and the Register component. We will be protecting the entire application by securing it. That means only an authenticated user will be allowed to view any data on the page. So, we will have a separate Layout Component for the Login/Register components. Let’s add this first.
Navigate to the Shared Folder with the Client project. Here is where you would ideally add any shared Razor Components. In our case, let’s add a new Razor Component and call it, AuthLayout.razor
You can see that it is quite a basic html file with an inherited tag. We will not concentrate on CSS/HTML in this series. However, this layout component is going to act as a container that will hold the Login and Register component within itself. Feel free to do all the fancy html stuff here.
PS, If you are going to add in css styles, I suggest you to add these properties in the site.css file located at the wwwroot/css folder to keep things organized.
Login Component
Create a new Razor Component under Pages/Authentication/Login.razor
Line 1 - Page route - ../login
Line 2 - Set the Layout to the AuthLayout component
Line 4 Injects our CustomStateProvider instance.
Then we have a bunch of HTML that defines a form with username and password input.
From Line 35, We define the Model object (LoginRequest) and build the function OnSubmit that gets fired when you submit the form with valid data. Here we just use the custom state provider to access the service and ultimately the api to verify the login.
Register Component
Similarly, we create a register component too under Pages/Authentication/Register.razor
You can see there are a bunch of unresolvable errors that probably say that a few items are not defined in the namespace or something. This is because we have not imported the new namespaces. To do this, navigate to _Import.razor and add these lines to the bottom.
Now, the error will go away. Now, we need to let Blazor know that we have authentication enabled and need to pass Authorize attribute throughout the application. For this, modify the Main Component, i.e., App.razor component.
What is AuthorizeRoteView?
It’s a combination of AuthorizeView and RouteView, so that is displays the specific page but only to users who are authorized.
What is CascadingAuthenticationState?
This provides a cascading parameter to all descendant components.
Let’s add a logout button to the top navigation of the application to allow the user to log out. We will have to make changes to the MainLayout.razor component for this.
And finally, we will need to display our username on the Index Component soon after we log in. Navigate to Pages/Index.razor and make the following changes.
Let’s test our Application now.
Summary
In this article, we have gone in-depth into Custom Authentication in Blazor WebAssembly. I will be updating this article with more data for you to learn. I hope this covers the entire Custom Authentication in Blazor WebAssembly. Let me know if I missed out on anything. You can find the completed source code here. Share this article within your developer community so that other developers can get a taste of Blazor! Happy Coding :D