User Registration & login Using Cookie Authentication ASP.NET Core

In this tutorial let us learn how to build a user registration / login & logout form using Cookie Authentication in ASP.NET Core. We will building it from scratch without using any third party libraries or ASP.NET Core identity. We will explore the ASP.NET Core identity in the next tutorial.

Create a New Application

Create a new ASP.NET Core web application either using Razor pages or ASP.NET Core MVC. For this tutorial, we are going to use the Razor pages (ASP.NET Core Web App). But you can as well use the MVC. We are using Visual Studio 2019 & .NET 5.0.

While creating the Project ensure that, you have selected Authentication Type as None. Also, name the project as AspNetCoreCookieAuthentication.

Run the app and check everything is ok.

User Entity

We will use the Entity Framework core to store the data in SQL Server. Hence, we need to Install the following packages.

Package Manager Console

Create a folder Data under the solution root and add the User.cs file. The User entity contains the Email & Password, which we will use to login the user into application.

Data/User.cs

Under the data folder create the context class ApplicationDbContext.cs. Note that we have a DbSet Property of the User Entity.

Data/ApplicationDbContext.cs

Add the connection string in appsettings.json

appsettings.json

Inject the DbContext in the Startup class using the AddDbContext extension method.

Startup.cs

Finally, Create the Database using EF Core Migration commands. You need to run the add-migration to create the migration script & update-database to create the database

Package Manager Console

Open the SQL Server and verify that the database ASPNetCookie is created with table User.

Creating database for Cookie Authentication
Creating database for Cookie Authentication

Securing the Product Page

Now, let us add Product Page. Select the Pages folder add a new Empty Razor page Product.cshtml.

We want only the logged in to our application to access the Product page. To do that we need to apply [Authorize] attribute to a controller, action, or Razor Page. This will stop the unauthenticated users from accessing the page

Product.cshtml

Product.cshtml.cs

We need to add a menu link to the Product Page in Home Page. Also we need to add menu link for Register & Login

Create the _LoginPartial.html under the folder Pages/Shared. We are going to add the menu link to Register & Login Pages here.

Pages/Shared/_LoginPartial.html

Open the layout.cshtml. Place the <partial name="_LoginPartial" />. Also add the link to Product Page. Relevant part of the _Layout.cshtml is shown below.

_Layout.cshtml

Adding Cookie Authentication

Now, our application is setup. Run the Application. Click on the Product Link and you will see the error

An unhandled exception occurred while processing the request.

InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found.

An unhandled exception occurred while processing the request

This is because, we have not configured any authentication services yet.

To make use of cookie authentication, we need to register the Cookie Authentication handler. This we do in AddAuthentication extension method

AddAuthentication

The AddAuthentication method returns the Authentication Builder, which we use to the register the Authentication handlers.

For Example, the following codes adds the Cookie Authentication handler using the method AddCookie

You can add more than one Authentication handlers using AddAuthentication. The following example, adds both Cookie Authentication & JwtBearer Authentication handler

Authentication scheme

Each handler that we add using the AddAuthentication becomes a new Authentication Scheme

A Authentication scheme consists of

  1. A unique Name, which identifies the Authentication scheme
  2. Authentication Handler
  3. Options for configuring that specific instance of the handler

In the code above, we have registered two authentication schemes. But neither, we have given them any name nor configured any of their options.

In such scenarios, these handlers registers the Authentication schemes using the Defaults. The Cookie Authentication handler defines all its defaults in the CookieAuthenticationDefaults class. Similarly, the JwtBearer uses the JwtBearerDefaults class

For Example, the Cookie Authentication uses the name “Cookies” (CookieAuthenticationDefaults.AuthenticationScheme) , while JwtBearer Authentication handler uses the “Bearer”. (JwtBearerDefaults.AuthenticationScheme)

The above code can also be written as follows, where we have provided the scheme name as the first argument. We have used the default names, but you can use any name you like.

Default Authentication scheme

When we use more than one Authentication Schemes, we also need to configure the default authentication scheme to use. We do that by specifying the Scheme name as the first argument to the AddAuthentication method.

In the example, we set the CookieAuthentication as the default. Wherever we do not mention the Authentication scheme, it will use the default scheme

Using Authentication Scheme

Authentication scheme name needs to be specified ,whenever you need to Authenticate the user. And if we do not specify it, then the default scheme is used.

For Example, the Authorize attribute accepts the argument AuthenticationSchemes, where you can specify the scheme to use to handle the authentication of the page or action.

Specifying the Authentication scheme is optional here. If you do not specify it, then the default Authentication scheme is used.

Finally, our Authentication code is looks at shown below

Cookie Authentication Defaults

Now run the application and click on Products link. You will see page can’t be found error.

This localhost page cant be found

The error says that we cannot access the https://localhost:44372/account/login page.

Only authorized users can access the Products Page. Since we are not authorized, we are redirected to the /account/login. page. Since we are yet to create the login page, we get the 404 error.

The /account/login is the default login page. It is configured in the CookieAuthenticationDefaults class. The following are the defaults defined in that class

You can change it if you wish to

User Register Form

The Register form asks for the Email & Password. On Clicking Register button it will save it to the Users table. Note that we are not Hashing the password. In real world, you must not store the password in plain text.

Once the user is registered, he is redirected to registration confirmation page.

Go to to Pages folder and create a new folder Account. Create the following files.

Pages/Account/_ViewImports.cshtml

Pages/Account/Register.cshtml

Pages/Account/Register.cshtml.cs

Pages/Account/RegisterConfirmation.cshtml

Pages/Account/RegisterConfirmation.cshtml.cs

Run the App and verify you are able to register the users.

Login Form

Now, let us create the Login Form in Pages/Account/ folder

Pages/Account/Login.cshtml

Pages/Account/Login.cshtml.cs

First, We are check to see if the user with the chosen password exists in the database.

Next, we need to add the Claims of the user to Claims collection.

A Claim is a piece of information about the user. It is consist of Claim type and optional value. It is stored in the form of name value pair. A Claim can be anything for example Name, Email, Roles, Phone Number, etc.

The ASP.NET Core uses the Claim based authorization. We attach the claims to a controller or an action using the Authorization Policies. The user is allowed only if they have the right claim.

Create the ClaimsIdentity using the Claims collection. We also need to specify the Authentication Scheme.

Create the ClaimsPrincipal from the ClaimsIdentity. A ClaimsPrincipal can contain more than one ClaimsIdentity.

Finally call SignInAsync of the HttpContext with the ClaimsPrincipal.

SignInAsync creates an encrypted cookie and adds it to the current response. There are few options like AllowRefresh, ExpiresUtc, IsPersistent, IssuedUtc & RedirectUri that you can set.

Now, Run the Application. Create a new User and login. Now click on Product Page. But you are still directed to login Page.

Authentication Middleware

Authentication Middleware authenticates the user. We add it to the middleware pipeline by using the UseAuthentication  extension method.

One of the important task that is performed by the built-in authentication middleware is to read the cookies 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, so that users are authenticated before accessing the endpoints.

startup.cs

Now, Run the Application. You should be able to access the Product Page after login.

Checking if User is Logged in

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

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

Logging Out

To Logout use the SignOutAsync method of the HttpContext.

Logout.cshtml

Logout.cshtml.cs

Listing the users Claims

You can read the claims of the user by iterating through the Claims collection of the ClaimsPrincipal (user Object).

Product.cshtml

Leave a Comment

Your email address will not be published.

Scroll to Top