asp.net core series 48 Identity identity model customization

1. Overview

ASP.NET Core Identity provides a framework for managing and storing user accounts in ASP.NET Core applications. Individual user accounts are selected as the authentication mechanism when Identity is added to a project. By default, Identity can use the Entity Framework (EF) Core data model. This article describes how to customize the identity model.

1.1 The following is the existing identity model, which consists of the following entity types:

Entity Type

Description

Relationship

Users (user table) Login user

Roles (role table)

Role

UserClaims (User Claim Form ) Permissions owned by users Every Users has Multiple UserClaims
UserTokens User’s authentication token Multiple UserTokens for each Users
UserLogins Associate users with logins. Each Users has multiple UserLogins
RoleClaims (role declaration table) Permissions owned by the role Every Each Roles has multiple RoleClaims
UserRoles User and role association Each Users has multiple Roles

(1) Users table

Field name

Field Type

Description

Id Guid Primary key, the default is Guid
UserName Nvarchar(256) Username or email
NormalizedUserName Nvarchar(256) Normalization Username, converted to uppercase
Email Nvarchar (256) Email
NormalizedEmail Nvarchar(256) Normalized mailbox name, converted to uppercase
EmailConfirmed bit Verification email confirmation, the default is false
PasswordHash Nvarchar(max) Password Hash
SecurityStamp Nvarchar(max) Security mark, Guid type, generate random when user credentials change Value, such as changing username
ConcurrencyStamp Nvarchar( max) Synchronization tag, Guid type
PhoneNumber Nvarchar(max) Telephone
PhoneNumberConfirmed bit> Phone Confirm
TwoFactorEnabled bit Two-factor authentication
LockoutEnd datetimeoffset(7) The expiration date of the lock, null means no lock
LockoutEnabled bit Whether it can be Lock
AccessFailedCount int Number of failed login attempts to determine whether to lock the user

1.2 Default model configuration

Identity defines a number of context classes that inherit from DbContext to configure and use the model. This configuration is done using the EF Core Code First Fluent API in the OnModelCreating method of the context class. For the default model structure, you can view the Migration file and the model relationship ModelSnapshot file, but if you want to modify the model, do not change it here. Below is the AspNetUsers model code:

The following is the data table and relationships generated by the default model:

2. Model customization

When rewriting the OnModelCreatingmethod in the EF context, the base.OnModelCreatingmethod is called first; then rewrite will override the default model configuration.

 public class ApplicationDbContext : IdentityDbContext<WebAppIdentityDemoUser>
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            :base(options)
        {
        }
        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);
            // Customize the ASP.NET Core Identity model and override the defaults if needed.
            // For example, you can rename the ASP.NET Core Identity table names and more.
            // Add your customizations after calling base.OnModelCreating(builder);
        }
    }

2.1 Custom user data

We talked about custom user data in the previous article, here is a summary. Custom user data is supported by inheriting the IdentityUser class. Custom class naming convention {Application}User.

 //Define {Application}User extension class to implement the user model
      public class WebAppIdentityDemoUser : IdentityUser
     //Using {Application}User as the type of the generic parameter of the context:
      public class ApplicationDbContext : IdentityDbContext<WebAppIdentityDemoUser>
      //Update Startup.ConfigureServices to use the new {Application}User class, and finally generate migrations and synchronize the database.
       services.AddDefaultIdentity<WebAppIdentityDemoUser>()
               .AddDefaultUI()
               .AddEntityFrameworkStores<ApplicationDbContext>(); 

?2.2 Change the primary key type

Changing the data type of a PK column after the database has been created is problematic on many database systems. Changing the PK usually involves dropping and re-creating the table. Therefore, when creating the database, the PK type should be specified in the initial migration. Here are the steps to change the primary key type:

(1) To delete the database, the command is as follows:

 Drop-Database 

(2) Remove the previously generated migration, the command is as follows:

 Remove-Migration

(3) Modify the user, role table primary key type, and related code changes

 // user table set primary key to Int
    public class WebAppIdentityDemoUser : IdentityUser<int>
    {
        /// <summary>
        /// Full name
        /// </summary>
        [PersonalData]
        public string Name { get; set; }

        /// <summary>
        /// Birth Date
        /// </summary>
        [PersonalData]
        public DateTime DOB { get; set; }
    }

   // The role table sets the primary key to Int
    public class WebAppIdentityDemoRole : IdentityRole<int>
    {

    }

(4) Modify context

 public class ApplicationDbContext : IdentityDbContext<WebAppIdentityDemoUser, WebAppIdentityDemoRole,int>

(5) Modify service registration

 services.AddIdentity<WebAppIdentityDemoUser, WebAppIdentityDemoRole>()
    //If you use the Identity scaffolder to add the Identity file to the project, please delete the call AddDefaultUI to the project
    //.AddDefaultUI()
     .AddEntityFrameworkStores<ApplicationDbContext>()
     ?.AddDefaultTokenProviders();

(6) Generate the migration code, the command is as follows

 Add-Migration IdentitySchema

(7) Synchronize database

  Update-Database IdentitySchema

At this time, the primary key type of the table has been modified, including the foreign key type of the relational table, which has also been updated simultaneously, as shown in the following figure:

?2.3 Add navigation attributes

Navigation properties only exist in the EF model, not in the database. If the navigation relationship has not changed, the model change does not need to update the database. Changing the model configuration of a relationship can be more difficult than making other changes. Care must be taken to replace existing relationships. The following example does not change the model relationship, but only adds navigation properties to the user model and specifies the relationship in the context:

 public class WebAppIdentityDemoUser : IdentityUser<int>
    {
        /// <summary>
        /// Full name
        /// </summary>
        [PersonalData]
        public string Name { get; set; }

        /// <summary>
        /// Birth Date
        /// </summary>
        [PersonalData]
        public DateTime DOB { get; set; }

        //Define navigation properties
        public virtual ICollection<IdentityUserClaim<int>> Claims { get; set; }
    }
 protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);
            // Customize the ASP.NET Core Identity model and override the defaults if needed.
            // For example, you can rename the ASP.NET Core Identity table names and more.
            // Add your customizations after calling base.OnModelCreating(builder);
            builder.Entity<WebAppIdentityDemoUser>(b =>
            {
                // Each User can have many UserClaims
                b.HasMany(e => e.Claims)
                    .WithOne()
                    .HasForeignKey(uc => uc.UserId)
                    .IsRequired();
            });
        }

For all user navigation properties, user and role navigation properties, add all navigation properties. Refer to the official website documentation.

2.4 Change table/column name, field length (change in context)

   protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);

            //Change table name
            builder.Entity<IdentityUser>(b =>
            {
                b.ToTable("MyUsers");
            });

            //Change table field name
            builder.Entity<IdentityUserClaim<string>>(b =>
            {
                b.Property(e => e.ClaimType).HasColumnName("CType");
                b.Property(e => e.ClaimValue).HasColumnName("CValue");
            });

            //change length
            builder.Entity<IdentityUser>(b =>
            {
                b.Property(u => u.UserName).HasMaxLength(128);
            });
        }

references

Custom Identity