Identity-Based Authentication In .NET Core 3.0 Using In-Memory Database

Introduction

 
Authentication is the process of determining or giving an individual access to a system or user based on their identity. There are multiple options to do authentication in .NET Core. This article demonstrates how to add Identity-Based Authentication in .NET Core 3.0 using In-Memory Database.
 
In the previous article, I have explained about Cookie-Based Authentication In .NET Core 3.0
 
Prerequisites
  • Install .NET Core 3.0.0 or above SDK from here.
  • Install the latest version of Visual Studio 2019 Community Edition from here.

Steps for Creating a Web Application

 
Step 1
 
Go to Visual Studio 2019, then select the "create new project" option from the options list.
 
Identity-Based Authentication In .NET Core 3.0 Using In-Memory Database
 
Step 2
 
After selecting that, a new window will open to select project template.
 
Step 3
 
Select “ASP.NET Core Web Application” and click on the Next button.
 
Identity-Based Authentication In .NET Core 3.0 Using In-Memory Database
 
Step 4
 
A new screen will open to configure your new project. Provide Project Name, Location, Solution Name as per your requirement. Press Create button.
 
Identity-Based Authentication In .NET Core 3.0 Using In-Memory Database
 
Step 5
 
After clicking on the Create button, a new screen will open to configure your project-related information like which environment you want create for the web application,  .NET Framework or .NET Core. Select .NET Core and ASP.NET Core Version from the drop down list. Then, select the web application (Model-View-Controller) option from the list and press the Create button to create a project.
 
Identity-Based Authentication In .NET Core 3.0 Using In-Memory Database
 
Step 6
 
Now our project will open with the basic structure of a .Net core environment. You can observe in the solution explorer that we will have Controllers, Models and View folders with “Startup.cs” and other files as well, like the below image.
 
Identity-Based Authentication In .NET Core 3.0 Using In-Memory Database
 
Step 7
 
Run your application to check whether the created web application is running fine or not. By default, it will open a Home page (Index page of Home controller) of your project.
 
Identity-Based Authentication In .NET Core 3.0 Using In-Memory Database
Install the below NuGet of version 3.0.0 or latest:
  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.InMemo
  • Microsoft.EntityFrameworkCore.Identity.EntityFrameworkCore 

Integrate Identity Authentication

  • IdentityDbContext - Provide all DbSet properties which are required to manage the identity tables.
  • ApplicationDbContext - User defined DbContext class inherits from IdentityDbContext to manage the user identity.
  • UseInMemoryDatabase - To store the user information for identity in memory insted of using any database.
  • AppUser - User defined class inherits from IdentityUser to add extra properties of user
  • UserManager - To manage user information like create user information, delete user information
  • SignInManager - Handle the communication with HttpContext as well as the user signin or signout functionality.
  • [Authorize] - An attribute that helps to validate user to an access controller (User Information)
Step 1
 
Create a new folder with the name Data and add ApplicationDbContext into it and put the below lines of code into it:
  1. using DemoIdentityAuthentication.Models;  
  2. using Microsoft.AspNetCore.Identity.EntityFrameworkCore;  
  3. using Microsoft.EntityFrameworkCore;  
  4.   
  5. namespace DemoIdentityAuthentication.Data  
  6. {  
  7.     // IdentityDbContext contains all the user tables  
  8.     public class ApplicationDbContext : IdentityDbContext<AppUser>  
  9.     {  
  10.         public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)  
  11.             : base(options)  
  12.         {  
  13.         }  
  14.     }  
  15. }  
Step 2
 
Add a new class into Models folder with name AppUser and put the below lines of code into it:
  1. using Microsoft.AspNetCore.Identity;  
  2.   
  3. namespace DemoIdentityAuthentication.Models  
  4. {  
  5.     public class AppUser : IdentityUser  
  6.     {  
  7.         public string Name { getset; }  
  8.         public string DateOfBirth { getset; }  
  9.         public string Password { getset; }  
  10.     }  
  11. }  
Step 3
 
Changes in Startup.cs file.
  1. using DemoIdentityAuthentication.Data;  
  2. using DemoIdentityAuthentication.Models;  
  3. using Microsoft.AspNetCore.Builder;  
  4. using Microsoft.AspNetCore.Hosting;  
  5. using Microsoft.AspNetCore.Identity;  
  6. using Microsoft.EntityFrameworkCore;  
  7. using Microsoft.Extensions.Configuration;  
  8. using Microsoft.Extensions.DependencyInjection;  
  9. using Microsoft.Extensions.Hosting;  
  10. using System;  
  11.   
  12. namespace DemoIdentityAuthentication  
  13. {  
  14.     public class Startup  
  15.     {  
  16.         public Startup(IConfiguration configuration)  
  17.         {  
  18.             Configuration = configuration;  
  19.         }  
  20.   
  21.         public IConfiguration Configuration { get; }  
  22.   
  23.         public void ConfigureServices(IServiceCollection services)  
  24.         {  
  25.             services.AddDbContext<ApplicationDbContext>(config =>  
  26.             {  
  27.                 // for in memory database  
  28.                 config.UseInMemoryDatabase("MemoryBaseDataBase");  
  29.             });  
  30.   
  31.             // AddIdentity :-  Registers the services  
  32.             services.AddIdentity<AppUser, IdentityRole>(config =>  
  33.             {  
  34.                 // User defined password policy settings.  
  35.                 config.Password.RequiredLength = 4;  
  36.                 config.Password.RequireDigit = false;  
  37.                 config.Password.RequireNonAlphanumeric = false;  
  38.                 config.Password.RequireUppercase = false;  
  39.             })  
  40.                 .AddEntityFrameworkStores<ApplicationDbContext>()  
  41.                 .AddDefaultTokenProviders();  
  42.   
  43.             // Cookie settings   
  44.             services.ConfigureApplicationCookie(config =>  
  45.             {  
  46.                 config.Cookie.Name = "DemoProjectCookie";  
  47.                 config.LoginPath = "/Home/Login"// User defined login path  
  48.                 config.ExpireTimeSpan = TimeSpan.FromMinutes(5);  
  49.             });  
  50.   
  51.   
  52.             services.AddControllersWithViews();  
  53.         }  
  54.   
  55.         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.  
  56.         public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  
  57.         {  
  58.             if (env.IsDevelopment())  
  59.             {  
  60.                 app.UseDeveloperExceptionPage();  
  61.             }  
  62.             else  
  63.             {  
  64.                 app.UseExceptionHandler("/Home/Error");  
  65.                 // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.  
  66.                 app.UseHsts();  
  67.             }  
  68.             app.UseHttpsRedirection();  
  69.             app.UseStaticFiles();  
  70.   
  71.             app.UseRouting();  
  72.   
  73.             app.UseAuthentication();  
  74.   
  75.             app.UseAuthorization();  
  76.   
  77.             app.UseEndpoints(endpoints =>  
  78.             {  
  79.                 endpoints.MapControllerRoute(  
  80.                     name: "default",  
  81.                     pattern: "{controller=Home}/{action=Index}/{id?}");  
  82.             });  
  83.         }  
  84.     }  
  85. }  
Step 4
 
Update HomeController with New Action Methods:
  1. Login: - For user login.
  2. Register: - For registering a new user.
  3. Logout: - To logout the current user.
  4. UserInfo with Authorize tag: -  To display user information for valid user and restrict access for invalid user. 
Put the below lines of code into HomeController.
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Diagnostics;  
  4. using System.Linq;  
  5. using System.Threading.Tasks;  
  6. using Microsoft.AspNetCore.Mvc;  
  7. using Microsoft.Extensions.Logging;  
  8. using DemoIdentityAuthentication.Models;  
  9. using Microsoft.AspNetCore.Identity;  
  10. using Microsoft.AspNetCore.Authorization;  
  11.   
  12. namespace DemoIdentityAuthentication.Controllers  
  13. {  
  14.     public class HomeController : Controller  
  15.     {  
  16.         private readonly UserManager<AppUser> _userManager;  
  17.         private readonly SignInManager<AppUser> _signInManager;  
  18.         public HomeController(  
  19.                    UserManager<AppUser> userManager,  
  20.                    SignInManager<AppUser> signInManager)  
  21.         {  
  22.             _userManager = userManager;  
  23.             _signInManager = signInManager;  
  24.         }  
  25.   
  26.         public IActionResult Index()  
  27.         {  
  28.             return View();  
  29.         }  
  30.   
  31.   
  32.         [Authorize]  
  33.         public async Task<IActionResult> UserInfo()  
  34.         {  
  35.             var user = await _userManager.GetUserAsync(HttpContext.User).ConfigureAwait(false);  
  36.                            
  37.   
  38.             if (user == null)  
  39.             {  
  40.                 RedirectToAction("Login");  
  41.             }  
  42.             //login functionality  
  43.   
  44.             return View(user);  
  45.         }  
  46.   
  47.         [HttpGet]  
  48.         public IActionResult Login()  
  49.         {  
  50.             return View();  
  51.         }  
  52.   
  53.         [HttpPost]  
  54.         public async Task<IActionResult> Login(AppUser appUser)  
  55.         {  
  56.   
  57.             //login functionality  
  58.             var user = await _userManager.FindByNameAsync(appUser.UserName);  
  59.   
  60.             if (user != null)  
  61.             {  
  62.                 //sign in  
  63.                 var signInResult = await _signInManager.PasswordSignInAsync(user, appUser.Password, falsefalse);  
  64.   
  65.                 if (signInResult.Succeeded)  
  66.                 {  
  67.                     return RedirectToAction("Index");  
  68.                 }  
  69.             }  
  70.   
  71.             return RedirectToAction("Register");  
  72.         }  
  73.   
  74.         public IActionResult Register()  
  75.         {  
  76.             return View();  
  77.         }  
  78.   
  79.         [HttpPost]  
  80.         public async Task<IActionResult> Register(AppUser appUser)  
  81.         {  
  82.             //register functionality  
  83.   
  84.             var user = new AppUser  
  85.             {  
  86.                 Id = "101",  
  87.                 UserName = appUser.UserName,  
  88.                 Email = appUser.Email,  
  89.                 Name = appUser.Name,  
  90.                 DateOfBirth = appUser.DateOfBirth,  
  91.                 Password = appUser.Password  
  92.             };  
  93.   
  94.             var result = await _userManager.CreateAsync(user, user.Password);  
  95.   
  96.   
  97.             if (result.Succeeded)  
  98.             {  
  99.                 // User sign  
  100.                 // sign in   
  101.                 var signInResult = await _signInManager.PasswordSignInAsync(user, user.Password, falsefalse);  
  102.   
  103.                 if (signInResult.Succeeded)  
  104.                 {  
  105.                     return RedirectToAction("Index");  
  106.                 }  
  107.             }  
  108.   
  109.             return View();  
  110.         }  
  111.   
  112.         public async Task<IActionResult> LogOut(string username, string password)  
  113.         {  
  114.             await _signInManager.SignOutAsync();  
  115.             return RedirectToAction("Index");  
  116.         }  
  117.     }  
  118. }  
Step 5 - Add view for HomeController
  1. Go to Views folder and select Home folder.
  2. Right click on the Home folder to select add option and select view.
  3. A window popup will open to add View.
  4. Provide View name as Login, select Template as Empty, select Use a layout page and press Add button. A new Login.cshtml file will be created in the Home folder. Refer to the image below to add view:

    Identity-Based Authentication In .NET Core 3.0 Using In-Memory Database

  5. Follow the same steps for other view as well and create a view for UserInfo action and Register action as well.
Code for the Login.cshtml page,
  1. @model DemoIdentityAuthentication.Models.AppUser  
  2.   
  3. <h1>User Login</h1>  
  4.   
  5. <form asp-controller="Home" asp-action="Login">  
  6.     <div class="form-group col-sm-6">  
  7.         <label for="Username">Username</label>  
  8.         <input type="text" class="form-control" id="Username" asp-for="UserName" placeholder="Enter username">  
  9.     </div>  
  10.     <div class="form-group col-sm-6">  
  11.         <label for="Password">Password</label>  
  12.         <input type="password" class="form-control" id="Password" asp-for="Password" placeholder="Enter password">  
  13.     </div>  
  14.     <div class="form-group col-sm-6">  
  15.         <button type="submit" class="btn btn-primary">Login</button>  
  16.     </div>  
  17. </form>  
Code for the Register.cshtml page,
  1. @model DemoIdentityAuthentication.Models.AppUser  
  2.   
  3. @{  
  4.     ViewData["Title"] = "Register";  
  5. }  
  6.   
  7. <h1>User Register</h1>  
  8.   
  9.   
  10. <form method="post" asp-controller="Home" asp-action="Register">  
  11.     <div class="form-group col-sm-6">  
  12.         <label for="Name">Name</label>  
  13.         <input type="text" class="form-control" id="Name" asp-for="Name" placeholder="Enter name">  
  14.     </div>  
  15.   
  16.     <div class="form-group col-sm-6">  
  17.         <label for="EmailId">Email Id</label>  
  18.         <input type="email" class="form-control" id="EmailId" asp-for="Email" placeholder="Enter email id">  
  19.     </div>  
  20.   
  21.     <div class="form-group col-sm-6">  
  22.         <label for="Username">Username</label>  
  23.         <input type="text" class="form-control" id="Username" asp-for="UserName" placeholder="Enter username">  
  24.     </div>  
  25.     <div class="form-group col-sm-6">  
  26.         <label for="Password">Password</label>  
  27.         <input type="password" class="form-control" id="Password" asp-for="Password" placeholder="Enter password">  
  28.     </div>  
  29.     <div class="form-group col-sm-6">  
  30.         <label for="DOB">Date Of Birth</label>  
  31.         <input type="text" class="form-control" id="DOB" asp-for="DateOfBirth" placeholder="Enter date of birth">  
  32.     </div>  
  33.     <div class="form-group col-sm-6">  
  34.         <button type="submit" class="btn btn-primary">Regiter</button>  
  35.     </div>  
  36. </form>  
Code for the UserInfo.cshtml page,
  1. @model DemoIdentityAuthentication.Models.AppUser  
  2.   
  3. <h1>User Information</h1>  
  4.   
  5. <table>  
  6.     <tr>  
  7.         <td>Name:- </td>  
  8.         <td>@Html.DisplayFor(model => model.Name)</td>  
  9.     </tr>  
  10.     <tr>  
  11.         <td>Email:- </td>  
  12.         <td>@Html.DisplayFor(model => model.Email)</td>  
  13.     </tr>  
  14.     <tr>  
  15.         <td>Username:- </td>  
  16.         <td>@Html.DisplayFor(model => model.UserName)</td>  
  17.     </tr>  
  18.     <tr>  
  19.         <td>Date Of Birth:- </td>  
  20.         <td>@Html.DisplayFor(model => model.DateOfBirth)</td>  
  21.     </tr>  
  22. </table>  
Step 6 - Update _Layout.cshtml Page
 
Update _Layout.cshtml page to add new tab/hyperlink for User Login, User Registration, User Information and for User Logout.
 
Code for _Layout.cshtml is as follows,
  1. <!DOCTYPE html>  
  2. <html lang="en">  
  3. <head>  
  4.     <meta charset="utf-8" />  
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0" />  
  6.     <title>@ViewData["Title"] - DemoIdentityAuthentication</title>  
  7.     <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />  
  8.     <link rel="stylesheet" href="~/css/site.css" />  
  9. </head>  
  10. <body>  
  11.     <header>  
  12.         <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">  
  13.             <div class="container">  
  14.                 <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">DemoIdentityAuthentication</a>  
  15.                 <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"  
  16.                         aria-expanded="false" aria-label="Toggle navigation">  
  17.                     <span class="navbar-toggler-icon"></span>  
  18.                 </button>  
  19.                 <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">  
  20.                     <ul class="navbar-nav flex-grow-1">  
  21.                         <li class="nav-item">  
  22.                             <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>  
  23.                         </li>  
  24.                         <li class="nav-item">  
  25.                             <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Register">Register</a>  
  26.                         </li>  
  27.                         <li class="nav-item">  
  28.                             <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Login">Login</a>  
  29.                         </li>  
  30.                         <li class="nav-item">  
  31.                             <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="UserInfo">User Information</a>  
  32.                         </li>  
  33.                         <li class="nav-item">  
  34.                             <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Logout">Logout</a>  
  35.                         </li>  
  36.                     </ul>  
  37.                 </div>  
  38.             </div>  
  39.         </nav>  
  40.     </header>  
  41.     <div class="container">  
  42.         <main role="main" class="pb-3">  
  43.             @RenderBody()  
  44.         </main>  
  45.     </div>  
  46.   
  47.     <footer class="border-top footer text-muted">  
  48.         <div class="container">  
  49.             © 2020 - DemoIdentityAuthentication - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>  
  50.         </div>  
  51.     </footer>  
  52.     <script src="~/lib/jquery/dist/jquery.min.js"></script>  
  53.     <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>  
  54.     <script src="~/js/site.js" asp-append-version="true"></script>  
  55.     @RenderSection("Scripts", required: false)  
  56. </body>  
  57. </html>  

Run Your Application

 
After successfully running your application, the output of your application should be like the screen below,
 
Identity-Based Authentication In .NET Core 3.0 Using In-Memory Database
Click on the User Information tab to get the current login user information, it will open a login page to login a user.
 
Question - Why will it ask for login?
 
Answer: [Authorize] attribute restricts access to data/information for unauthorized requests and redirects to a login page to check whether user is valid or not. In our case, we have added this attribute over the UserInformation action method of HomeController.
 
Register your account before going to login. Click on the Register tab and provide user information as per the below screen,
 
Identity-Based Authentication In .NET Core 3.0 Using In-Memory Database
 
After successful registration, it will create a cookie in the browser like below,
Identity-Based Authentication In .NET Core 3.0 Using In-Memory Database
 
Now, click on the Login tab and enter username and password like the below screen,
 
Identity-Based Authentication In .NET Core 3.0 Using In-Memory Database
Click on the UserInformation tab again and now you can find the final result of user information without asking for login.
 
Identity-Based Authentication In .NET Core 3.0 Using In-Memory Database
 

Summary

 
In this article, I discussed how to add Identity-Based Authentication in .NET Core 3.0 using In-Memory Database. We have also created a user login and registration forms to login a user to our application to access useful information. I hope this will help the readers to understand how to implement the identity-based authentication in any application. Please find the attached code for better understanding.