ASP.NET Core Identity and fully customize the database structure instead of using Dapper EntityFramework Core

Foreword

Originally this section does not exist, for a few people asked me: I want to use ASP.NET Core Identity, but I do not want to use the database tables generated by default, want to customize a set, I want to use ASP. NE Core Identity and do not want to use EntityFramework Core. Really high maintenance, ha ha, but I think that the issues raised are very valuable, so I spent some time in private to see Xiaguan network information, or engage in a final attempt to pass out, do not know whether to satisfy asked me this question several children's shoes without further ado, we go directly to the subject again.

ASP.NET Core Identity Custom database table structure

Ha Do not worry, I'm the kind of person from the beginning talked about the end, Bowen basically for the general public, there is no foundation of experience and are slow connection, and do not hold anything against my long-winded, well, I'm done, start, start, and said a lot. For the most part we are by default inherited from the default identity-related categories, as follows:

    /// <summary>
    /// 
    /// </summary>
    public class CusomIdentityDbContext : IdentityDbContext<CustomIdentityUser, CustomIdentityRole, string>
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="options"></param>
        public CusomIdentityDbContext(DbContextOptions<CusomIdentityDbContext> options)
        : base(options)
        { }
    }

    /// <summary>
    /// 
    /// </summary>
    public class CustomIdentityUser : IdentityUser { }

    /// <summary>
    /// 
    /// </summary>
    public class CustomIdentityRole : IdentityRole { }

Then add identity middleware, and finally begin the migration, as follows:

            services.AddIdentity<CustomIdentityUser, IdentityRole>()
                     .AddEntityFrameworkStores<CusomIdentityDbContext>()
                     .AddDefaultTokenProviders();

            services.AddDbContextPool<CusomIdentityDbContext>(options =>
             options.UseSqlServer(Configuration.GetConnectionString("Default")));

These are the default data tables generated for us, we can specify a user table's primary key, you can modify the table names, column names, and so on, as well as extended attributes on this basis are possible, but we just do not want to use this set, you need to self define a set of tables to manage user identity information, so we are going to help them? Actually, the official website for tips,

The following links: https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity-custom-storage-providers?view=aspnetcore-2.2 , but that's not very clear, and some children's shoes on a loss, it is that several Store, custom implementations like to, we go a. We first customize the user, such as the following:

    /// <summary>
    /// 
    /// </summary>
    public class User
    {
        /// <summary>
        /// 
        /// </summary>
        public string Id { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string UserName { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string Password { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string Phone { get; set; }
    }

Let's define the context, as follows:

    /// <summary>
    /// 
    /// </summary>
    public class CustomDbContext : DbContext
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="options"></param>
        public CustomDbContext(DbContextOptions<CustomDbContext> options) : base(options)
        {
        }

        /// <summary>
        /// 
        /// </summary>
        public DbSet<User> Users { get; set; }
    }

Next to realize IUserStore and UserPasswordStore interface, the interface too much, all folded

    /// <summary>
    /// 
    /// </summary>
    public class CustomUserStore : IUserStore<User>, IUserPasswordStore<User>
    {
        private readonly CustomDbContext context;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        public CustomUserStore(CustomDbContext context)
        {
            this.context = context;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="user"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<IdentityResult> CreateAsync(User user, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="user"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<IdentityResult> DeleteAsync(User user, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="disposing"></param>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                context?.Dispose();
            }
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<User> FindByIdAsync(string userId, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="normalizedUserName"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<User> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="user"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<string> GetNormalizedUserNameAsync(User user, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="user"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<string> GetPasswordHashAsync(User user, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="user"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<string> GetUserIdAsync(User user, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="user"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<string> GetUserNameAsync(User user, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="user"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<bool> HasPasswordAsync(User user, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="user"></param>
        /// <param name="normalizedName"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task SetNormalizedUserNameAsync(User user, string normalizedName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="user"></param>
        /// <param name="passwordHash"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task SetPasswordHashAsync(User user, string passwordHash, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="user"></param>
        /// <param name="userName"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task SetUserNameAsync(User user, string userName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="user"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<IdentityResult> UpdateAsync(User user, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }
    }
View Code

We have to use user roles table, custom user roles

    /// <summary>
    /// 
    /// </summary>
    public class CustomUserRole
    {
        /// <summary>
        /// 
        /// </summary>
        public string Id { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string UserId { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string RoleId { get; set; }
    }

Then again achieve user roles Store, as follows:

    /// <summary>
    /// 
    /// </summary>
    public class CustomUserRoleStore : IRoleStore<CustomUserRole>
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="role"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<IdentityResult> CreateAsync(CustomUserRole role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="role"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<IdentityResult> DeleteAsync(CustomUserRole role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        public void Dispose()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="roleId"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<CustomUserRole> FindByIdAsync(string roleId, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="normalizedRoleName"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<CustomUserRole> FindByNameAsync(string normalizedRoleName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="role"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<string> GetNormalizedRoleNameAsync(CustomUserRole role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="role"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<string> GetRoleIdAsync(CustomUserRole role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="role"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<string> GetRoleNameAsync(CustomUserRole role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="role"></param>
        /// <param name="normalizedName"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task SetNormalizedRoleNameAsync(CustomUserRole role, string normalizedName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="role"></param>
        /// <param name="roleName"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task SetRoleNameAsync(CustomUserRole role, string roleName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="role"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<IdentityResult> UpdateAsync(CustomUserRole role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }
    }

It is simply necessary to see whether or not to implement the following several Store Bale

  • IUserRoleStore
  • IUserClaimStore
  • IUserPasswordStore
  • IUserSecurityStampStore
  • IUserEmailStore
  • IPhoneNumberStore
  • IQueryableUserStore
  • IUserLoginStore
  • IUserTwoFactorStore
  • IUserLockoutStore

For the self-Store then select the custom implementation have to register and migration, as follows:

            services.AddIdentity<CustomUser, CustomUserRole>()
                    .AddDefaultTokenProviders();

            services.AddDbContextPool<CustomDbContext>(options =>
             options.UseSqlServer(Configuration.GetConnectionString("Default")));

            services.AddTransient<IUserStore<CustomUser>, CustomUserStore>();

 

No problem, then again, a custom implementation, however, is to achieve a built-in Store, other context defined by the user can be normal to manage. What then landed, and the like only need to register the corresponding generic parameters such as UserManager replaced by their corresponding CustomUser such as can be, this would not have to speak more. Next we look at the second question, but how not to use EntityFramework full use of Dapper.

Dapper full use instead of using EntityFramework Core

In fact, a complete explanation of the first question, this is solved, we have fully implemented a custom set of tables, the first question is operating table by context, we simply replace Dapper context can, as we define user roles table, that we realize the role of the table by Dapper, roles are defined as follows:

    /// <summary>
    /// 
    /// </summary>
    public class CustomRole
    {
        /// <summary>
        /// 
        /// </summary>
        public string Id { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string Name { get; set; }
    }
    /// <summary>
    /// 
    /// </summary>
    public class CustomRoleStore : IRoleStore<CustomRole>
    {
        private readonly IConfiguration configuration;
        private readonly string connectionString;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="configuration"></param>
        public CustomRoleStore(IConfiguration configuration)
        {
            this.configuration = configuration;
            connectionString = configuration.GetConnectionString("Default");
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="role"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<IdentityResult> CreateAsync(CustomRole role, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            using (var connection = new SqlConnection(connectionString))
            {
                await connection.OpenAsync(cancellationToken);
                role.Id = await connection.QuerySingleAsync<string>($@"INSERT INTO [CustomRole] ([Id],[Name])
                VALUES (@{Guid.NewGuid().ToString()} @{nameof(CustomRole.Name)});
                SELECT CAST(SCOPE_IDENTITY() as varchar(36))", role);
            }

            return IdentityResult.Success;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="role"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<IdentityResult> DeleteAsync(CustomRole role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        public void Dispose()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="roleId"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<CustomRole> FindByIdAsync(string roleId, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="normalizedRoleName"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<CustomRole> FindByNameAsync(string normalizedRoleName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="role"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<string> GetNormalizedRoleNameAsync(CustomRole role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="role"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<string> GetRoleIdAsync(CustomRole role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="role"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<string> GetRoleNameAsync(CustomRole role, CancellationToken cancellationToken)
        {
            return Task.FromResult(role.Name);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="role"></param>
        /// <param name="normalizedName"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task SetNormalizedRoleNameAsync(CustomRole role, string normalizedName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="role"></param>
        /// <param name="roleName"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task SetRoleNameAsync(CustomRole role, string roleName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="role"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<IdentityResult> UpdateAsync(CustomRole role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }
    }

Do not forget that every custom achieve a Store, then the corresponding register

 services.AddTransient<IRoleStore<CustomRole>, CustomRoleStore>();

to sum up

Here it has provided a complete set of tables and custom implementation of ideas does not use EntityFramework Core full use of Dapper, reiterating an official website gives a few Store, but it is not explicitly stated, a little thinking and hands-on verification, in fact, not a big problem.

Guess you like

Origin www.cnblogs.com/CreateMyself/p/11291623.html