ASP.NET Core Identity is described by Microsoft as "a membership system which allows you to add login functionality to your application"; it brings a huge amount of user account functionality to our web applications with almost no effort on the part of the developer.
We are going to look at what happens when you add Identity to a project, how to customise the type of the primary key and how to implement a multi-tenant Identity solution.
Creating a new "ASP.NET Core Web Application" project in Visual Studio offers the option to "Change Authentication" to "Individual User Accounts"; doing so will add all the code required to support Identity. Whilst this is fantastically easy for the developer, having all the work done for us does tend to make it more difficult to understand how it actually works, which can make it difficult to understand how to customise or extend Identity when it doesn't do exactly what we need out of the box.
Before we progress with some of the common customisations we have required at Future Shock, it helps to understand what happens when Identity is added to a project:
The really important bits here are 3a and 4; these are the areas we will need to tweak if we wish to customise our Identity configuration, so we will quickly examine these in a bit more detail.
This is where the overall configuration of our application occurs, a number of lines have been added to support Identity mostly in the ConfigureServices method:
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
This adds the database definition class to the list of services supported by our application, and tells the service to use the database connection string added in the appsettings.json. Simply adding this wires an application up to use a database (assuming the Microsoft.EntityFrameworkCore NuGet package is installed, your ApplicationDbContext could derive from the DbContext class in EntityFrameworkCore - for more info see the official ASP.NET Core docs).
This adds the Identity service, telling it to use the class in Models/ApplicationUser.cs to define the IdentityUser, to use the default IdentityRole class, to use the database context we created in step 1, and to add all the remaining defaults for Identity using AddDefaultTokenProviders. This is the key configuration point for customising Identity. Note that in theory the custom class ApplicationUser could be removed and the IdentityUser class supplied with Identity used instead, but you would need to edit many of the MVC files to do this; its simpler to use the ApplicationUser class and which will be required for many of the more common simple customisations of Identity (e.g. adding other fields to your user account than simply those supplied to support login).
services.AddTransient<IEmailSender, AuthMessageSender>(); and
These add the services for sending emails and text messages.
The Configure method has simply gained the code
app.UseIdentity(); in ASP.NET Core 1 (
app.UseAuthentication(); in ASP.NET Core 2) to actually enable Identity in the application pipeline.
Knowing what has been automatically added to support Identity, and having identified the key points of customisation, we can now look at a few commonly required changes.
The primary key created automatically for the User table in our database will be of type string by default; many of us will require something different to use in relationships as we implement the feature set our application. Generally we use
guid types for this purpose; changing this in versions of Identity before Core could be quite a lot of work, thankfully it has become much easier now.
We are giving an example of changing to a
long but you can use any other type in its place.
You can find more information on this in the official ASP.NET Core documentation but below is the most simplified process we have found for both current versions of ASP.NET Core.
We have found it only necessary to amend the IdentityUser, there is no need to customise IdentityRole to change its key type.
public class ApplicationUser : IdentityUser
public class ApplicationUser : IdentityUser<long>
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, IdentityRole<long>, long>
longand that IdentityRole also needs to use a corresponding
longkeys for Users and Roles.
user.Id.ToString()on the four lines that cause an error.
add-migration SetupDatabase -OutputDir Data\Migrations
The only difference from the ASP.NET Core version 1 instructions above is in step 3 where the
AddEntityFrameworkStores line has changed to not require or accept a second parameter, it should now be amended to:
As this is a fairly in-depth topic we have published this in a separate article