Hot to custom Identity Tables Model on .Net Core 2.2

21 Jul 2019, CSHARP , IDENTITY

1752 Palavras, por José luiz

#Security , #Auth , #User , #Identity , #Custom Table



Intro

Whats up Developers, Everything is ok today? When you start your projects in .NET Core and don’t know how to customize your Identity Model tables? or, don’t know how to create them in the database? So today I want to present you with a simple solution so you can customize the tables on IDENTITY and get to use this incredible tool that NET provides to us.

What I want to share is a simple technique, you can use the idea here and apply in your projects.


Identity Model


I’m using Visual Studio Code, with the .NET Core 2.2 version in a MariaDB (Docker) database, if you do not know how to configure MariaBD to work with .NET Core, take a look at my other Post that will help you.

  1. Create MVC Project
  2. Adding MariaDB Dependency
  3. Send default table to DB
  4. Change the name tables
  5. Change type primary key in tables
  6. Create new field on User Tables
  7. Extra Tip! Clean Code +

#1 Create MVC Project


I am using .NET CLI to create the projects since we are using VS Code so, to create the project we will open our console and type:

 dotnet new mvc --auth Individual

  • mvc: Means that I want create a MVC project
  • –auth Individual: Responsable for add all API with user authentication using some database.

After create the projects you can type on console to run your site

 dotnet run

In this template the .NET Core comes parameterized for connection in SQL Lite, which I do not want, so let’s add the whole MariaDB library.

#2 Adding MariaDB Dependency


Now we will add the dependencies of MariaDB to our project, this POST is not about that however, I will leave the commands here, just follow the steps below that there will be no error.

1 - Remove the SQL Lite library

 dotnet remove package Microsoft.EntityFrameworkCore.Sqlite

2 - Add the dependencies of MariaDB to our project

dotnet add package Pomelo.EntityFrameworkCore.MySql

3 - Change the file Startup.cs to use MariaDB Where was UseSqlLite change to UseMySql

 services.AddDbContext<ApplicationDbContext>(options =>
                options.UseMySql(
                    Configuration.GetConnectionString("DefaultConnection")));

4 - Run the commands, to restore and run respectively to verify that the project has no error ..

dotnet restore
dotnet run

5 - Finalize just changing the appsettings.json file to configure the string connection with your DB MariaDB (or any other)

Server=localhost;User Id=root;Password=password;Database=CusomTable

Now your project is ready, and is this part that we are going to analyze the standard Identity Tables

#3 Send default table to DB


First of all, we will create the default Identity tables to understand how it works so we will use the EntityFramework Core commands which will help us create the tables using Migrations, this is not our goal “talk about migrations”, I will write a post about it .

But I need to quickly explain what is Migrations that nothing else is a feature that has been added to the Entity Framework that will do all the work of creating the database and tables in our project, in an “automagic”. Remember that we created the string connection, but we did not create the database or the tables.

Come on, run the command below:

 dotnet ef migrations add MyFistMigrationEF

.NET will create a folder named migrations in your project, browsing!, and you will understand what EF does is simply create a “map” to create the tables, do not change these files, Let’s do something more professional here.

After running the migration command, you need to perform within the Database that you have configured in the ConnectionString. To do this, run the command below that EF will do for you:

 dotnet ef database update  

This command will create the DB (if it does not exist) and will apply all the migrations that you have created …

If we open our DB Manager (I’m using DBeaver), we see our DB created:

DB Create

But something is not cool, right? If you look at the name of the tables are standard this is what we will do in the next step, change the name of the tables

#4 Change the name tables


I could say that “changing the name is so easy to steal candy from a child” but I would not know, since I have never stolen candy from a child. But what I know that changing and customizing the name is extremely easy.

Just open the file of our Context, in this case .NET CORE created a called ApplicationDbContext.cs, we will open it and add some codes in OnModelCreating as below

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

namespace CustomIdentity.Data {
    public class ApplicationDbContext : IdentityDbContext {
        public ApplicationDbContext (DbContextOptions<ApplicationDbContext> options) : base (options) { }

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

            //Change my AspNetUser table to User
            builder.Entity<IdentityUser> ().ToTable ("User");

            //Change my AspNetRoles to Role
            builder.Entity<IdentityRole> ().ToTable ("Role");

        }
    }
}

You can customize all the tables here, I’m just changing the name of two, thus you can understand the process.

Ok, now to apply within the Database, just create another Migration and send to the bank:

dotnet ef migrations add CustomMyTables

Finally, run the command below to send to the Database

 dotnet ef database update   

Now when you open the database, you will see the names of the changed tables…

DB Create

But still not cool yet?, see that the primary key of the User table is string ..

DB Create

Let’s change?

#5 Change type primary key in tables


To change the type of primary key to INT let’s create one file that will help us in next step also, this file will be extend the class IdentityUser.

So, create a file called IdentityCustomTables.cs inside of the project and put this code:

  using Microsoft.AspNetCore.Identity;

namespace CustomIdentity.Data {
    public class CustomUserTable : IdentityUser<int> {

    }

    public class CustomRoleTable : IdentityRole<int> {

    }
}

The class IdentityUser accept generics types to use in primary key in tables.

Just to show the class, do not code

  //     The type used for the primary key for the user.
  public class IdentityUser<TKey> where TKey : IEquatable<TKey>

That means I can determine the key type, the default is string, and we are changing to INT. Also see that I’m changing the key for two tables, Users and Roles.

After creating the file we need change the context to use this file so that EF understands what should be done, then change the ApplicationDbContext.cs to:

Note that we also changed OnModelCreating and passed the class we created, if you do not you will receive an error when committing your changes.

  public class ApplicationDbContext : IdentityDbContext<CustomUserTable, CustomRoleTable, int> {

    // ... Code Hide

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

            //Change my AspNetUser table to User
            builder.Entity<CustomUserTable> ().ToTable ("User");

            //Change my AspNetRoles to Role
            builder.Entity<CustomRoleTable> ().ToTable ("Role");

        }
  }

Next step?? Ahhh easy, let’s create the migration and apply in the Database, but wait:

Erroe!!!

Calm down, I know that you’ve got the error below:

violates the constraint of type "TUser".
Unable to create an object of type "ApplicationDbContext". 
For the different patterns supported at design time, see ...

This is why now we are working with different file in Identity, and we should also change in the file Setup.cs so that the .NET engine also works with the same file and no more with Standard Identity

Just change from:

services.AddDefaultIdentity<IdentityUser> ()
                .AddDefaultUI (UIFramework.Bootstrap4)
                .AddEntityFrameworkStores<ApplicationDbContext> ();

to:

 services.AddIdentity<CustomUserTable, CustomRoleTable> ()
                .AddDefaultUI (UIFramework.Bootstrap4)
                .AddEntityFrameworkStores<ApplicationDbContext> ();

By the Way, I need to remove the database and create again, WHY??

Why is the User table already related to other Identity tables like Claim and we have a decision to make: Do we create a migration to change other tables, or do we delete the database and create it again?

Since the project is in the beginning and we are using Code First, deleting this Database makes more sense! Because it does not contain data, but in real cases, you should stay awake!

To delete the DB run the command:

 dotnet ef database drop

We will also remove all Migration, because if we apply the same migration again, we will return in the same step/error, EF will create the DB with the key string and then will try to change the column to INT…

Just delete the project Migrations folder

After drop the DB and deleting the migration folder we can finally create the new migration and apply it to the bank

 dotnet ef migrations add MyFinallCustomTable
 dotnet ef database update   

Ahh, I love Entity Framework Core <3

Now It’s ok, if we open the Database you’ll see the PK as INT… Pretty cool isn’t?

#6 Create new field on User Tables

To create new fields/properties, just change the file that we created to change the type of the primary key reminds? IdentityCustomTables.cs

then just create the fields that you want:

using Microsoft.AspNetCore.Identity;

namespace CustomIdentity.Data {
    public class CustomUserTable : IdentityUser<int> {

        // custom properties
        public string FirstName { get; set; }
        public byte[] Photo { get; set; }
        public string PasswordTip { get; set; }

    }

    public class CustomRoleTable : IdentityRole<int> {

    }
}

Of course, it has to be properties then create a migration and send to the Database

 dotnet ef migrations add MyFinallCustomField
 dotnet ef database update   

#7 Extra Tip! Clean Code +

  • You can change the type of columns by placing the type you want within the ApplicationDbContext.cs file
        protected override void OnModelCreating (ModelBuilder builder) {
            base.OnModelCreating (builder);

            // hide code

            //custom type of column
            builder.Entity<CustomUserTable> ()
                .Property (e => e.FirstName)
                .HasColumnType ("varchar(50)").IsUnicode (false);

        }
  • In order for your ApplicationDbContext.cs to not get too large you can create the Identity configuration file in a separate folder and import it into the ApplicationDbContext.cs

To do this, just create a file in your project called IdentityMigration.cs:

  
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore.Metadata.Internal;

namespace CustomIdentity.Data {
    public class IdentityMigration : IEntityTypeConfiguration<CustomUserTable> {
        public void Configure (EntityTypeBuilder<CustomUserTable> builder) {
            builder.ToTable ("User");
            builder.HasKey (p => p.Id);

            builder.Property (e => e.FirstName)
                .HasColumnType ("varchar(50)").IsUnicode (false);
        }

    }

    public class RoleMigration : IEntityTypeConfiguration<CustomRoleTable> {
        public void Configure (EntityTypeBuilder<CustomRoleTable> builder) {
            builder.ToTable ("Role");
        }
    }
}

Make the Import in the ApplicationDbContext.cs Class

   // code hide
        protected override void OnModelCreating (ModelBuilder builder) {
            base.OnModelCreating (builder);
            builder.ApplyConfiguration (new IdentityMigration ());
            builder.ApplyConfiguration (new RoleMigration ());

        }
   // code hide

Finally

Customizing application is a common procedure and understanding the mechanics behind it is vital to our control, fortunately the .NET Core leaves us with great power in our hands, but remember:

With power comes responsibility. ;)

Makes sense to you?

GitHub Project

Let’s goooooo…..

Note...

Hy, I'm José Luiz and my commitment is to no bullshit post, no sponsored posts, no ads, and no paywalls.

If you enjoy my content, please consider supporting what I do.

Support my work and save the World!

All support is send to MSF & O Bem nunca para :)