Introduction
It is a membership system that allows us to add login functionality to our application. A user may create an account and log in using credentials or can use external login providers, such as Google, Microsoft Account, Twitter, Facebook, etc.
We can configure ASP.NET Core Identity to use SQL Server database to store the user profile data or we can use our own persistent store, such as Azure Table Storage.
We can either create an application using Visual Studio or .NET Core CLI.
In VS, select File => New => Project, and select ASP.NET Core Web Application from the popup.
After that, select Web Application (Model-View-Controller) for framework 2.x with Individual User Account as an authentication mode.
Using .NET Core CLI, we can create a new project using the "dotnet new MVC --auth Individual" command. This will create a new project with the same template as mentioned above, using Visual Studio.
Command
dotnet new mvc --auth Individual
Configure Identity Services
The ConfigureServices method of startup class contains configuration for the Identity Services. The "services.AddIdentity" method adds the default identity system configuration for specific users and roles. These services are available to the application using DI (dependency injection).
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
// ...
// Additional service configurations
// ...
}
Identity Services are enabled for the application by calling the "UseAuthentication" method on the Configure method of the startup class. This method adds authentication middleware to the request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// ...
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
The template creates classes to represent role, user, and database context that, from the framework classes, inherits IdentityRole, IdentityUser, and IdentityDbContext.
public class ApplicationUser : IdentityUser
{
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
}
}
public class AppIdentityRole : IdentityRole
{
}
This template also added a default connection string to the appsetting.json file. In this connection string, the default database name is "aspnet-{project name}-{guid}". For demonstration, I have changed it to "IdentityTest".
appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=IdentityTest;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
}
}
Now, I am launching the application and clicking the Register link. It will display the following page. Insert the required information and click on the Register button. If this is the first time, your system will ask for database migrations.
By clicking on "Apply Migrations", you can migrate the database. Alternatively, we can also use the command line to perform the migration. Just, use the following command.
dotnet ef database update
The migration will generate identity-related tables in the database.
We can also test ASP.NET Core Identity with our application without a persistent database by using an in-memory database. To use an in-memory database, we need to add Microsoft.EntityFrameworkCore.InMemory package to our application and modify the "AddDbContext" call with the following code in the ConfigureServices method of the Startup class.
services.AddDbContext<ApplicationDbContext>(options =>
options.UseInMemoryDatabase(Guid.NewGuid().ToString()));
The "Register" action of AccountController is invoked when the user clicks on the "Register" link. This action method creates a user by calling the "CreateAsync" method of the UserManager class. The UserManager class is provided to the controller class by using dependency injection.
public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
_logger.LogInformation("User created a new account with password.");
await _signInManager.SignInAsync(user, isPersistent: false);
_logger.LogInformation("User created a new account with password.");
return RedirectToLocal(returnUrl);
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
SignIn and SignOut
The ASP.net core Identity provides a class called "SignInManager" that is used to authenticate the user and sign-in (login) or sign-out user. This "SignInManager" class is provided to the controller by using dependency injection.
The "SignInManager" class has various methods for Sign, such as PasswordSignInAsync, SignInAsync, etc. It also contains the method for external logins, such as ExternalLoginSignInAsync. This class contains the method "SignOutAsync" for signing out the user from the system. Apart from that, this class has methods for checking the user lock status, resetting the lock, locking the user, refreshing the token, etc.
// For Sign in
await _signInManager.SignInAsync(user, isPersistent: false);
// For Sign out
await _signInManager.SignOutAsync();
Override default Configuration
We can also override the default behavior of the Identity class. There is no configuration required if we want to use a default configuration. The configuration for Identity can be changed by defining IdentityOption in the ConfigureServices method of the startup class.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
//services.AddDbContext<ApplicationDbContext>(options =>
// options.UseInMemoryDatabase(Guid.NewGuid().ToString()));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
// Override the configuration
services.Configure<IdentityOptions>(options =>
{
// Password settings
options.Password.RequireDigit = true;
options.Password.RequiredLength = 8;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = true;
options.Password.RequireLowercase = false;
// Lockout settings
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(60);
options.Lockout.MaxFailedAccessAttempts = 10;
options.Lockout.AllowedForNewUsers = true;
// User settings
options.User.RequireUniqueEmail = true;
});
services.ConfigureApplicationCookie(options =>
{
// Cookie settings
options.Cookie.HttpOnly = true;
options.Cookie.Expiration = TimeSpan.FromDays(150);
options.LoginPath = "/Account/Login";
options.LogoutPath = "/Account/Logout";
options.AccessDeniedPath = "/Account/AccessDenied";
options.SlidingExpiration = true;
});
// Add application services
services.AddTransient<IEmailSender, EmailSender>();
services.AddMvc();
}
Summary
We can add Identity in ASP.NET Core using very a few lines of simple code that add registration, login, logout, forgot, and reset password features to our application. ASP.NET Core Identity will take care of everything, such as password hashes, validating tokens, finding users, inserting users, etc.