ASP.NET Core Identity Tutorial

In this ASP.NET Core Identity Tutorial, we will show you how to create ASP.NET Core web application with Identity from scratch. We will build an ASP.NET Core application without Authentication and add the identity-related Components. Let us add User Registration & Login & logout Forms. This will help you understand the ASP.NET Core Identity API better.

The Tutorial works on ASP.NET Core 2.1 or later.

ASP.NET Core Identity

ASP.NET Core Identity is a fully featured membership system for creating and maintaining user logins. Using Identity API, you can sign in & sign out users, reset their passwords , lockout users & Implement Multi Factor Authentication. It can also integrate with the external login providers like Microsoft Account, Facebook, Google, etc.

When we create a new application, we can install the ASP.NET Core identity by choosing the Individual Accounts under the Authentication Type Option. Most of the Identity related services and UI forms like Register, Login & Logout are automatically created for us.

In this tutorial, we will create the project with No Authentication and then we will add the Identity API. In this way you will learn the Identity API better.

The Identity API uses cookie Authentication. We have also have a tutorial about User Registration & login Using Cookie Authentication. That tutorial does not use the identity API. The Identity API uses the techniques mentioned in the tutorial. Hence we advices you to go through it first.

The Two important Identity services are User Manager and Sign In Manager.

User Manager 

The UserManager is a concrete class that manages the user. This Class Creates, Updates, and Deletes the Users. It has methods to find a user by User ID, User Name, and email. UserManager also provides the functionality for adding Claims, removing Claims, add and removing roles, etc. It also generates password hash, Validates Users etc.

Sign In Manager

SignInManager is a concrete class which handles the user sign in from the application.

The SignInManager is responsible for Authenticating a user, i .e  signing in and signing out a user. It issues the authentication cookie to the user. 

Create new ASP.NET Core Project

Open a New Project in Visual Studio 2019.

Choose ASP.NET Core Web App Template and name the Project as ASPNetCoreIdentity 

Choose the Platform as .NET 5.0. Select Authentication as No Authentication. Click OK to create the new Project

Create new ASP NET Core Identity Project

Run the project to check if everything is alright.

Installing Identity API

Next step is to install the Identity API.

We will be using Entity Framework Core with Identity. Hence we need to install Identity EF Core Package.

SQL Server is going to be our database.

Need EF Core Tools to generate EF Core Migrations

Preparing the Database

Connection String

The Database Connection strings are stored in appsettings.json file. Open the and add the connection string as follows

appsettings.json

Identity Models

The Microsoft.AspNetCore.Identity namespace contains the Entity Models of the Identity API. They are

  1. IdentityRole
  2. IdentityRoleClaim
  3. IdentityUser
  4. IdentityUserClaim
  5. IdentityUserLogin
  6. IdentityUserRole
  7. IdentityUserToken

You can inspect the properties directly from the Identity API Source Code

For Example, the following is the IdentityUser entity model.

IdentityUser.cs

This class captures the important information about the user.

Note that we need to specify the Type, that we use for the Primary Key. The Identity API by default uses string type for Id and stores GUID values in it.

If you want, you can also add additional properties to the above fields. To do that you need to create another class (for example, ApplicationUser) and inherit from the IdentityUser. Add the properties you wish to add to the ApplicationUser class. Use the ApplicationUser class instead of the IdentityUser everywhere.

Database Context

The DBContext is the class, which provides API to interact between EF Core entity models and the database. We usually create our context class inheriting from the DBContext class.

ASP.NET Core Identity API already implements IdentityDbContext class, which inherits from the DBContext class. It already includes the DbSet Properties for the Identity Models.

Hence we create the our applications DbContext class, inheriting from the IdentityDbContext

Go to the Project folder create a folder Data.

In the Data folder create a class ApplicationDbContext.cs and add the following code

Data/ApplicationDbContext.cs

Note that we need to specify the types that we use for User, Role and Type of Primary Key to the IdentityDbContext.

If, you have overridden these types in the application, then use those Types here.

Registering the DBContext in Startup

The ASP.NET core uses dependency injection framework, where you can simply ask for the required services in the constructor of the class. To do that first we need to configure the services in the startup class

Open the Startup class from the root folder

Locate the ConfigureServices method. This is where we are going to configure all the services for dependency injection

The AddDbContext expects us to provide the Type that we will use for Context class, which is ApplicationDbContext.

The options.UseSqlServer lets us use the SQL Server

The connection string is retrieved from the Configuration.GetConnectionString(“DefaultConnection”)

Migrations

Next, step is to create the database. To do that we use the EF Core Migrations. Run the add-migration and then update-database to create the database

Open and inspect the database. You will see following tables.

ASPNET Core Identity Database

The following table explains the role of each table with their entity name

EntityTable NameRemarks
IdentityUserAspNetUsersPrimary table to store user information
IdentityUserClaimAspNetUserClaims tables holds the claims associated with the user.
IdentityUserLoginAspNetUserLogins table holds the information about 3rd party/external logins
IdentityUserTokenAspNetUserTokens is for storing tokens received from the external login providers.
IdentityUserRoleAspNetUserRoles table contains the roles assigned to the user
IdentityRoleAspNetRoles tables to store the roles
IdentityRoleClaimAspNetRoleClaims The claims that are assigned to the Role

Run the App and check everything is working again

Registering the Identity Services

In the startup class, we also need to register the Identity related services. To do that we use the AddIdentity extension method

Locate the ConfigureServices method in the startup class and add the following code before the AddRazorPages() method.

AddIdentity method takes types used for User (IdentityUser) & Roles (IdentityRole). If you have overridden them in your code, then use them

The AddIdentity method registers various services like UserValidator, PasswordValidator, PasswordHasher, UserManager, Cookie-based authentication schemes. SignInManager etc. We can inject these services in our controller, Razor pages or views via Dependency Injection

You can also specify the the various options that you can set to customize the identity. We set the RequireConfirmedAccount to false. Otherwise, the user is not allowed to login until we send a email confirmation link to him and he confirms it by clicking on it.

Finally AddEntityFrameworkStores takes types used for the context (ApplicationDbContext) and registers the stores related services.

Authentication Middleware

Authentication Middleware reads the authentication cookies from the incoming request and construct the ClaimsPrincipal and update the User object in the HttpContext.

This will make the all the middleware’s which appear after the UseAuthentication() is aware that the user is authenticated.

We must invoke the UseAuthentication

  • After UseRouting, so that route information is available for authentication decisions.
  • Before UseEndpoints & UseAuthorization, so that users are authenticated before accessing the endpoints.

Open the startup class and locate the Configure method. Add the UseAuthentication after the UseRouting method

startup.cs

Building the UI

Next, let use build User Registration, Login & Logout Forms. But before that, we need to add the scripts needed for client side validation and few layout changes.

We are structuring the our application in line with how Identity API works. The Identity API creates the Area Identity and all the razor pages are added to the folder Account. Hence we also follow that.

Under the solutions node create the folder Areas/Identity/Pages/Account

Under the folder Areas/Identity/Pages add a new Partial Razor page _ValidationScriptsPartial.cshtml. This page includes the scripts that we need to perform the client side validation. We will add this Partial Page to register & login pages.

Areas/Identity/Pages/_ValidationScriptsPartial.cshtml

Under the folder Areas/Identity/Pages add another Partial Page _ViewImports.cshtml.

_ViewImports uses the Razor directives to import namespaces and use dependency injection. All the Views & Razor pages in the folder and its sub folder will use it. We do not have to import these name spaces in every razor pages or views.

Areas/Identity/Pages/_ViewImports.cshtml

Next, add _ViewStart.cshtml. Here we set the Layout page for all Pages under the Areas/Identity/Pages/ folder.

Areas/Identity/Pages/_ViewStart.cshtml

Similarly, another _ViewImports file in the Accounts folder.

Areas/Identity/Pages/Accounts/_ViewImports.cshtml

Protecting the Page

Now, open the Pages/Privacy.cshtml.cs Page.

Add the Authorize attribute to PrivacyModel class as shown below. With the Authorize attribute, only the authenticated user can access the Privacy page.

Run the App and navigate to Privacy Page.

As expected the Privacy page does not open. Instead the user is redirected to the /Account/Login URL. Since the /Account/Login does not exist, the browser throws the 404 error.

This Localhost page cant be found in ASP.NET Core Identity

How does it know to redirect the user to /Account/Login Page.

The /Account/Login is the default page, where Cookie Authentication middleware redirects the User, if he is not authenticated. We can change it in the startup class.

The Identity API defines its login, logout & AccessDenied pages to /Identity/Account/ URL. Add the following code before the AddRazorPages() method in the ConfigureServices method of the startup class.

The Privacy page now redirects us to the /Identity/Account/Login page instead of /Account/Login.

Login & Register Menu

Let us create a menu option for Register.

Under Views -> Shared Create a Partial View _LoginPartial.cshtml and add the following code.

Views/Shared/_LoginPartial.cshtml

Our Application uses the Views/Shared/_layout.cshtml as the common layout.

Locate the <div class="navbar-collapse in the above file and copy the following code after that div element.

Views/Shared/_layout.cshtml

User Registration

Create a new Razor Page Register under the folder Areas/Identity/Pages/Account

Areas/Identity/Pages/Account/Register.cshtml

Note that we have included the _ValidationScriptsPartial in Scripts Section.

Areas/Identity/Pages/Account/Register.cshtml.cs

Decorate with AllowAnonymous so that anyone can view the page

We Inject UserManager & SignInManager into our Razor Page.

On GET Request, we read the ReturnUrl, so that we can redirect the user to the page where he came from, once he registers successfully.

When User registers OnPostAsync method executes

After the Model is validated, new IdentityUser is created and CreateAsync method of the UserManager creates the new user.

If the Registration is successful, the SignInAsync method of SignInManager Signs in the user. The user is redirected to the ReturnUrl

The Identity API has the ability to generate & send the email confirmation links. We have intentionally, omitted that from here.

Password Validation

Now, run the app and enter password as 123456. You will see the password validation message.

Password Validation in Register Form

The password validation happens at client side as well as server side. The Client Side validation done using the _ValidationScriptsPartial.

At the server side CreateAsync method runs the password & other validations, before creating the User.

We can set options for validating the Passwords while configuring the Identity Services in the startup class. If we do not specify it, then the Identity Services will use the defaults.

You can change the defaults as shown below.

Login Form

Create a new Razor Page Login under the folder Areas/Identity/Pages/Account

Areas/Identity/Pages/Account/Login.cshtml

Areas/Identity/Pages/Account/Login.cshtml.cs

Decorate with AllowAnonymous so that anyone can view the page

We Inject UserManager & SignInManager into our Razor Page.

On GET Request, we read the ReturnUrl, so that we can redirect the user to the page where he came from, once he registers successfully.

We use the SignOutAsync() method of the HttpContext, which clears the existing external cookie if any to ensure a clean login process. Note that user is not logged out.

When User registers OnPostAsync method executes

Once the model is validated, we sign in the user using the PasswordSignInAsync method of the SignInManager.

The PasswordSignInAsync method does the following

  1. Verify the user exists and password matches
  2. Password / email does not match then returns with Succeeded set to false
  3. Creates the ClaimsIdentity with Claims of the User.
  4. Creates the ClaimsPrincipal from the ClaimsIdentity
  5. Invokes the HTTPContext.SignInAsync method with the ClaimsPrincipal.
  6. Returns with Succeeded set to true

The SignInAsync method creates an encrypted cookie and adds it to the current response. The Current response is returned to User. The User browser reads the cookie from the response and stores it securely. When user sends another request to the server, the browser sends the cookie along with the request.

The Authentication Middleware ( Registered with UseAuthentication() in the startup class ) reads the Cookie, decrypts it and recreates the ClaimsPrincipal. It then updates the User property of HttpContext with ClaimsPrincipal.

To access the ClaimsPrincipal of the current user all you need to do is the access the HttpContext.User property

Now, run the app & check register & login functions

Displaying the Login User Name

To check if the User is logged in or not, we can use the User Property. The User Property is nothing but an instance of ClaimsPrincipal. It is automatically injected into the Controller Or Razor Pages.

The User.Identity.Name returns the current user name, We use that to display the user name

Modify the _LoginPartial.cshtml to show the login & Register link only if the user is not logged in. If he is logged in, then show the Logout link.

_LoginPartial.cshtml

Logout

Create the Logout Razor Page under the folder Areas/Identity/Pages/Account/

Areas/Identity/Pages/Account/Logout.cshtml

Areas/Identity/Pages/Account/Logout.cshtml.cs

SignOutAsync() method of the SignInManager removes the authentication cookie from the context & response. This will automatically logs out the user.

Summary

This ASP.NET Core Identity Tutorial showed how to implement Identity without using the template. We Built Login, Logout & User Registration forms. The Identity API has lots of features to offer apart from login & logout. We will cover that in our next tutorial

Reference

Introduction to Identity on ASP.NET Core

Leave a Comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top