Introduction
Authentication is the process of determining or giving an individual access to 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.
Background
In the previous article, I 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
- Go to Visual Studio 2019, then select Create a new project from option list.
- After selecting that, a new window will open to select project template.
- Select “ASP.NET Core Web Application” and click on Next button.
- A new screen will open to configure your new project. Provide Project Name, Location, Solution Name as per your requirement. Press Create button.
- After clicking on Create button, a new screen will open to configure your project related information like which environment you want to create for web application? .NET Framework or .NET Core. Select .NET Core and ASP.NET Core Version from drop down list. Then, select web application (Model-View-Controller) option from list and press Create button to create a project.
- Now our project will open with the basic structure of .NET Core environment. You can observe in the solution explorer that will have Controllers, Models and Views folders with “Startup.cs” and other files as well like the below image:
- 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.
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 tabels ApplicationDbContext
: User defined DbContext
class inherits from IdentityDbContext
to manage the user identity UseInMemoryDatabase
: To store the user information for identity in memory instead 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]
: Attribute helps to validate user to an access controller (User Information)
Step 1
Create a new folder with name as Data and add ApplicationDbContext
into it and put the below lines of code into it:
using DemoIdentityAuthentication.Models;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace DemoIdentityAuthentication.Data
{
public class ApplicationDbContext : IdentityDbContext<AppUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
}
}
Step 2
Add a new class into Models folder with name AppUser
and put the below lines of code into it:
using Microsoft.AspNetCore.Identity;
namespace DemoIdentityAuthentication.Models
{
public class AppUser : IdentityUser
{
public string Name { get; set; }
public string DateOfBirth { get; set; }
public string Password { get; set; }
}
}
Step 3
Changes in Startup.cs file:
using DemoIdentityAuthentication.Data;
using DemoIdentityAuthentication.Models;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
namespace DemoIdentityAuthentication
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(config =>
{
config.UseInMemoryDatabase("MemoryBaseDataBase");
});
services.AddIdentity<AppUser, IdentityRole>(config =>
{
config.Password.RequiredLength = 4;
config.Password.RequireDigit = false;
config.Password.RequireNonAlphanumeric = false;
config.Password.RequireUppercase = false;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.ConfigureApplicationCookie(config =>
{
config.Cookie.Name = "DemoProjectCookie";
config.LoginPath = "/Home/Login";
config.ExpireTimeSpan = TimeSpan.FromMinutes(5);
});
services.AddControllersWithViews();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
Step 4
Update HomeController
with New Action Methods:
- Login: For user login
- Register: For registering a new user
- Logout: To logout current user
- UserInfo with Authorize tag: To display user information for valid user and restrict to get an access for invalid user
Put the below lines of code into HomeController
:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using DemoIdentityAuthentication.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Authorization;
namespace DemoIdentityAuthentication.Controllers
{
public class HomeController : Controller
{
private readonly UserManager<AppUser> _userManager;
private readonly SignInManager<AppUser> _signInManager;
public HomeController(
UserManager<AppUser> userManager,
SignInManager<AppUser> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
public IActionResult Index()
{
return View();
}
[Authorize]
public async Task<IActionResult> UserInfo()
{
var user =
await _userManager.GetUserAsync(HttpContext.User).ConfigureAwait(false);
if (user == null)
{
RedirectToAction("Login");
}
return View(user);
}
[HttpGet]
public IActionResult Login()
{
return View();
}
[HttpPost]
public async Task<IActionResult> Login(AppUser appUser)
{
var user = await _userManager.FindByNameAsync(appUser.UserName);
if (user != null)
{
var signInResult = await _signInManager.PasswordSignInAsync
(user, appUser.Password, false, false);
if (signInResult.Succeeded)
{
return RedirectToAction("Index");
}
}
return RedirectToAction("Register");
}
public IActionResult Register()
{
return View();
}
[HttpPost]
public async Task<IActionResult> Register(AppUser appUser)
{
var user = new AppUser
{
Id = "101",
UserName = appUser.UserName,
Email = appUser.Email,
Name = appUser.Name,
DateOfBirth = appUser.DateOfBirth,
Password = appUser.Password
};
var result = await _userManager.CreateAsync(user, user.Password);
if (result.Succeeded)
{
var signInResult = await _signInManager.PasswordSignInAsync
(user, user.Password, false, false);
if (signInResult.Succeeded)
{
return RedirectToAction("Index");
}
}
return View();
}
public async Task<IActionResult> LogOut(string username, string password)
{
await _signInManager.SignOutAsync();
return RedirectToAction("Index");
}
}
}
Step 5
Add view
for HomeController
:
- Go to Views folder and select Home folder.
- Right click on the Home folder to select add option and select view.
- A window popup will open to add View.
- Provide View name as
Login
, select Template as Empty
, select Use a layout page and press Add button. A new Login.cshtml file will create into Home folder. Refer to the image below to add view:
- Follow the same steps for other views as well and create a view for
UserInfo
action and Register
action as well. - Code for the Login.cshtml page:
@model DemoIdentityAuthentication.Models.AppUser
<h1>User Login</h1>
<form asp-controller="Home" asp-action="Login">
<div class="form-group col-sm-6">
<label for="Username">Username</label>
<input type="text" class="form-control"
id="Username" asp-for="UserName"
placeholder="Enter username">
</div>
<div class="form-group col-sm-6">
<label for="Password">Password</label>
<input type="password" class="form-control" id="Password"
asp-for="Password" placeholder="Enter password">
</div>
<div class="form-group col-sm-6">
<button type="submit" class="btn btn-primary">Login</button>
</div>
</form>
@model DemoIdentityAuthentication.Models.AppUser
@{
ViewData["Title"] = "Register";
}
<h1>User Register</h1>
<form method="post" asp-controller="Home" asp-action="Register">
<div class="form-group col-sm-6">
<label for="Name">Name</label>
<input type="text" class="form-control"
id="Name" asp-for="Name" placeholder="Enter name">
</div>
<div class="form-group col-sm-6">
<label for="EmailId">Email Id</label>
<input type="email" class="form-control"
id="EmailId" asp-for="Email" placeholder="Enter email id">
</div>
<div class="form-group col-sm-6">
<label for="Username">Username</label>
<input type="text" class="form-control"
id="Username" asp-for="UserName" placeholder="Enter username">
</div>
<div class="form-group col-sm-6">
<label for="Password">Password</label>
<input type="password" class="form-control"
id="Password" asp-for="Password" placeholder="Enter password">
</div>
<div class="form-group col-sm-6">
<label for="DOB">Date Of Birth</label>
<input type="text" class="form-control"
id="DOB" asp-for="DateOfBirth" placeholder="Enter date of birth">
</div>
<div class="form-group col-sm-6">
<button type="submit" class="btn btn-primary">Register</button>
</div>
</form>
- Code for the UserInfo.cshtml page:
@model DemoIdentityAuthentication.Models.AppUser
<h1>User Information</h1>
<table>
<tr>
<td>Name:- </td>
<td>@Html.DisplayFor(model => model.Name)</td>
</tr>
<tr>
<td>Email:- </td>
<td>@Html.DisplayFor(model => model.Email)</td>
</tr>
<tr>
<td>Username:- </td>
<td>@Html.DisplayFor(model => model.UserName)</td>
</tr>
<tr>
<td>Date Of Birth:- </td>
<td>@Html.DisplayFor(model => model.DateOfBirth)</td>
</tr>
</table>
Step 6
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:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - DemoIdentityAuthentication</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm
navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area=""
asp-controller="Home"
asp-action="Index">DemoIdentityAuthentication</a>
<button class="navbar-toggler" type="button"
data-toggle="collapse" data-target=".navbar-collapse"
aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area=""
asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area=""
asp-controller="Home" asp-action="Register">Register</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area=""
asp-controller="Home" asp-action="Login">Login</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area=""
asp-controller="Home"
asp-action="UserInfo">User Information</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area=""
asp-controller="Home" asp-action="Logout">Logout</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
© 2020 - DemoIdentityAuthentication - <a asp-area=""
asp-controller="Home" asp-action="Privacy">Privacy</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@RenderSection("Scripts", required: false)
</body>
</html>
Run Your Application
After successfully running your application, output of your application should be like the screen below:
- Click on 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 to access data/information for unauthorized requests and redirects to 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:
- After successful registration, it will create a cookie in the browser like below:
-
Now, click on the Login tab and enter username and password like the below screen:
Click on the UserInformation tab again and now you can find the final result of user information without asking for login.
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 readers to understand how to implement the identity-based authentication in any application. Please find the attached code for better understanding.
History
- 31st January, 2020: Initial version