Introduction
Blazor is a new framework built by Microsoft for creating interactive client-side web UI with a .NET codebase. We can write both client-side and server-side code in C#.NET itself. I have already written six articles about the Blazor server on C# Corner. Please refer to the below articles for more basics about the Blazor framework.
Microsoft provides an identity framework for authentication and authorization in the Blazor application by default. Please note, currently they are using MVC Core razor pages for authentication UI. They use the “Microsoft.AspNetCore.Identity.UI” package library to achieve this. In the future, they may replace this with Razor components. In this post, we can see how to add authentication and authorization for the Blazor application and restrict pages with user roles. I will explain all these actions step by step.
Choose the Blazor template in Visual Studio 2019 and click the “change” option under authentication.
Choose the “Individual User Accounts” type and keep the default “Store user accounts in-app” to store SQL tables locally for identity framework.
After choosing the authentication type, you can click the “Create” button to create the project.
If you check the NuGet package manager, you can see below packages are installed in the project automatically.
You can also notice that a migration script file is created under the “Migrations” folder along with the “ApplicationDbContext” class file.
We can execute below Package Manager Console command below to create an SQL database and tables related to the identity framework. If needed, you can modify the SQL connection string in the appsettings.json file. By default, a unique database name is given in the appsettings.json file.
update-database
The above command will create a new database and seven tables in the database for identity users and roles.
We are not using all these seven tables in our Blazor application. We will use the “AspNetUsers” table for storing user information. We will use the “AspNetRoles” table for storing role information. We will also use the “AspNetUserRoles” table to store role details for a user.
We can modify the “ConfigureServices” method in the “Startup” class with the below change. So that we can control the authorization with identity roles in the application.
ConfigureServices method in the Startup class.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>()
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();
services.AddSingleton<WeatherForecastService>();
}
We can run the application and create two different users by clicking the register button. By default, no roles will be added for these users. We will add different roles for each user.
We can create a new user by clicking the “Register” button.
We have created a new user “[email protected]” as a username. We can create one more user “[email protected]”. Currently, no roles are created. We can add two roles “Admin” and “Normal” into the table “AspNetRoles”.
We can add user roles to the table “AspNetUserRoles”. We need a user ID along with a role id. You can copy the corresponding user ID from the AspNetUsers table.
I have added the first user with an admin role id and the second user with a normal role ID.
We can create two Razor components “Admin” and “Normal” inside the “Pages” folder. The Admin component will be accessible for admin users and the Normal component will be accessible for both admin and normal users. We must decorate these components with the Authorize attribute later.
We can create a second component “Normal” in the same way.
Modify the shared component “NavMenu” with below changes. So that, these new components will be visible only for authorized users.
NavMenu.razor
<p class="top-row pl-4 navbar navbar-dark">
<a class="navbar-brand" href="">BlazorAuth</a>
<button class="navbar-toggler" @onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
</p>
<p @class="NavMenuCssClass" @onclick="ToggleNavMenu">
<ul class="nav flex-column">
<li class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
</NavLink>
</li>
<AuthorizeView Roles="Admin">
<li class="nav-item px-3">
<NavLink class="nav-link" href="admin">
<span class="oi oi-list-rich" aria-hidden="true"></span> Admin Component
</NavLink>
</li>
</AuthorizeView>
<AuthorizeView Roles="Admin, Normal">
<li class="nav-item px-3">
<NavLink class="nav-link" href="normal">
<span class="oi oi-list-rich" aria-hidden="true"></span> Normal Component
</NavLink>
</li>
</AuthorizeView>
</ul>
</p>
@code {
bool collapseNavMenu = true;
string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
}
I have modified the above component with a Blazor attribute “AuthorizeView” along with the “Roles” property. First NavLink is assigned with Admin roles and second NavLink is assigned with Admin and Normal roles. Hence, this link will be visible for both Admin and Normal users. Run the application again and log in as an admin user.
We can notice that the navigation links for the Admin component and Normal component are visible for this admin user. If you log in with a normal user, only the Normal component link will be visible. You can notice one important thing even without login, these two components are accessible via the direct page route. We have not yet restricted these components. We can use the “Authorize” attribute to restrict these components for authorized users.
We can modify the Admin component with the below changes.
We have added the Authorize attribute along with the Roles property in this component.
Admin. razor
@page "/admin"
@attribute [Authorize(Roles = "Admin")]
<h3>Admin Component</h3>
<p>This page is only accessible to users with 'Admin' roles</p>
@code {
}
We can modify the Normal component with the below changes.
Normal. razor
@page "/normal"
@attribute [Authorize(Roles = "Admin, Normal")]
<h3>Normal Component</h3>
<p>This page is only accessible to users with 'Admin' or 'Normal' roles</p>
@code {
}
In the above component, we have decorated the Authorize attribute with both Admin and Normal roles.
Run the application again as a normal user and try to access the Admin component by directly entering the route in the browser.
You will get an unauthorized access error message on the page. We have successfully implemented role-based authorization in two components.
Conclusion
In this post, we have seen how to create a Blazor application with individual user account authentication. We have created all seven tables for the identity framework using entity framework database migration. Later, we added two different identity users by clicking the register button in the application. We have added two roles Admin and Normal manually to the table. We have also added user roles into the other table with the corresponding user id and role id. We have added an authorization attribute in the NavMenu component to control the visibility of components with corresponding roles. We have decorated Admin and Normal components with Authorize attribute and Roles property to restrict unauthorized access to these components. This is only a basic application to show authentication and authorization in the Blazor app. I will create more real projects with authentication and custom authorization in the forthcoming days. Please feel free to share your valuable feedback about this post.