ASP.NET Core Identity is an API that supports login functionality in ASP.NET Core MVC web application. Login information can be stored in identity when creating a new user account. Identity can be configured with SQL Server database to store user details such as username, password and email id. So in this article I will explain how to use identity to register, login and logout of a user account.
Creating ASP.NET Core MVC web application
Create ASP.NET Core MVC web application as follows
Select ASP.NET Core Web Application from the template and provide the project name and location where this project can be saved.
Select MVC template along with ASP.NET Core latest version and click on create button for the application to be created. Now we have to add ASP.NET Core Identity in our application. To add identity right click on the project name, click on Add option and the click on New Scaffolded Item.
Select the Identity option and click on Add button. Now we can select login and register razor pages from ASP.NET Core Identity.
Select the layout page for the razor pages, provide the data context class for database related operations and User class to customize the given registration razor page. Now click on Add button.
As we can see identity is added inside Areas folder. Inside Area folder both data as well as razor pages have been added. Now we have to add user authentication into this application, for that we have to modify startup.cs class. We have to add support for razor pages inside the application.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddRazorPages();
}
Inside ConfigureServices method, we have to call the function AddRazorPages. To include identity into this application we have to call UseAuthentication function inside configure method.
app.UseAuthentication();
Now we need to add url’s for login and register pages, for that we have to call a function called MapRazorPages inside UseEndpoints.
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
Now we need to create database for the application.
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
namespace LoginAuth.Areas.Identity.Data
{
// Add profile data for application users by adding properties to the ApplicationUser class
public class ApplicationUser : IdentityUser
{
[PersonalData]
[Column(TypeName="nvarchar(100)")]
public string FirstName { get; set; }
[PersonalData]
[Column(TypeName = "nvarchar(100)")]
public string LirstName { get; set; }
}
}
Here we are adding properties for first name and last name. Inside user table it will be personal data, that is why we need to add attribute personal data. We can also define the data types of each property with the help of attribute column.
Now we have to perform migration operation to insert these newly created properties inside the SQL Server database.
For that go to tools, then click on Nuget Package Manager. Click on Package Manager Console.
To create Migration, we can execute Add-Migration command.
To update the database, execute command Update-Database.
We can see the newly created database LoginAuthDB in SQL Server below
In order to display form controls for first name and last name inside registration form, we have to update the input model inside register.cshtml.cs file by adding corresponding properties inside the input model.
public class InputModel
{
[Required]
[DataType(DataType.Text)]
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "Last Name")]
public string LirstName { get; set; }
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
We also need to add the same inside the OnPostAsync function for saving the record.
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = Input.Email, Email = Input.Email,FirstName = Input.FirstName,LirstName = Input.LirstName };
var result = await _userManager.CreateAsync(user, Input.Password);
if (result.Succeeded)
{
_logger.LogInformation("User created a new account with password.");
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { area = "Identity", userId = user.Id, code = code },
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
if (_userManager.Options.SignIn.RequireConfirmedAccount)
{
return RedirectToPage("RegisterConfirmation", new { email = Input.Email });
}
else
{
await _signInManager.SignInAsync(user, isPersistent: false);
return LocalRedirect(returnUrl);
}
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
// If we got this far, something failed, redisplay form
return Page();
}
Here we are passing both first name and last name.
Now we need to update the registration form inside Register.cshtml
@page
@model RegisterModel
@{
ViewData["Title"] = "Register";
}
<h1>@ViewData["Title"]</h1>
<div class="row">
<div class="col-md-4">
<form asp-route-returnUrl="@Model.ReturnUrl" method="post">
<h4>Create a new account.</h4>
<hr />
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.FirstName"></label>
<input asp-for="Input.FirstName" class="form-control" />
<span asp-validation-for="Input.FirstName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.LirstName"></label>
<input asp-for="Input.LirstName" class="form-control" />
<span asp-validation-for="Input.LirstName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.Email"></label>
<input asp-for="Input.Email" class="form-control" />
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.Password"></label>
<input asp-for="Input.Password" class="form-control" />
<span asp-validation-for="Input.Password" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.ConfirmPassword"></label>
<input asp-for="Input.ConfirmPassword" class="form-control" />
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Register</button>
</form>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
A new user can now register in our application. After filling the login information and clicking on login button, once the user is logged in to the application corresponding email id link and logout button can be displayed by including _LoginPartial.cshtml file inside _Logout.cshtml file 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"] - LoginAuth</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">LoginAuth</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">
<partial name="_LoginPartial.cshtml" />
</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 - LoginAuth - <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>
We can also provide authentication feature to the application so that only authenticated users will be able to login inside the application. For that we have add Authorize attribute inside Home Controller as follows.
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 LoginAuth.Models;
using Microsoft.AspNetCore.Authorization;
namespace LoginAuth.Controllers
{
[Authorize]
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
return View();
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
Output
If we run the application, we will be redirected to login page because user is not authenticated.
Registered user details are stored inside SQL Server database as follows
Once a user is logged in, the user will be redirected to the home page.
Summary
In this article, we have discussed to how to create Registration and login functionalities in ASP.NET Core web application using Identity. We have added register and login razor pages to register a new user and store user details using identity inside SQL Server database. We also modified the existing registration page by adding first name and last name properties inside the register. cshtml file. We also provided authentication feature to the application so that only authenticated user will be able to login inside the application.