One of the first issues you will likely encounter when getting started with ASP.NET Identity centers on customizing the underlying data model. The Entity Framework provider uses Code-First to generate the data model and, initially, it may seem as if it is imposing its model upon your application. Fortunately, since the implementation of the provider uses Code-First, we can make significant customizations to the model and still take advantage of the features that ASP.NET Identity and EF provide.

In part one of this series, we will customize the ASP.NET Identity data model by simply changing the default schema and renaming the tables. In part two of this series, we will add audit fields to some of the tables and change the primary key data types from GUIDs to integers.

To get started, let’s generate the default data model to see what we are working with:

  1. Start by creating a new ASP.NET MVC and/or Web API project. Be sure the Authentication Mode is set to “Individual User Accounts” so the project template pulls in the required references, as well as the scaffolding for the default security model.
  2. Update the default connection string (“DefaultConnection”) in the web.config to point to your SQL Server database.
  3. Build and run the application.

Next, navigate to the login page and attempt to sign in with any credentials. Your login attempt will fail because no accounts are registered, but the Entity Framework should have generated the default data model for users, roles, and claims. If you check the database, you will find something similar to the following:

That is all well and good and if you have worked with the Membership Provider for .NET, you should be reasonably comfortable with what you see. However, we are interested in customizing the model; so let’s get started by renaming the tables and moving them into our application schema.

Step 1: Create the object model

To get started, add the following classes to your project. These classes form the object model that will be mapped to the data model. If you are following along in the attached sample project, you will find these classes under the NAM_Sample_Pt1.Models namespace.

ApplicationUserRole.cs

public class ApplicationUserRole : IdentityUserRole { }

ApplicationRole.cs

public class ApplicationRole : IdentityRole<string, applicationuserrole=""> { }

ApplicationUserClaim.cs

public class ApplicationUserClaim : IdentityUserClaim { }

ApplicationUserLogin.cs

public class ApplicationUserLogin : IdentityUserLogin { }

IdentityModels.cs

Update the ApplicationUser class with the following:

public class ApplicationUser : IdentityUser<string, applicationuserlogin,="" applicationuserrole,="" applicationuserclaim="">
{
    public async Task GenerateUserIdentityAsync(ApplicationUserManager manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        return userIdentity;
    }

Step 2: Create the EF data context

Create a new security data context in IdentityModels.cs according to the following definition:

public class ApplicationDbContext : IdentityDbContext<applicationuser, applicationrole,="" string,="" applicationuserlogin,="" applicationuserrole,="" applicationuserclaim="">
{
    public ApplicationDbContext() : base("DefaultConnection") { }     public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }
}

Note that the data context inherits from IdentityDbContext, which is the generic base data context that is included in the EF Provider for Identity. IdentityDbContext includes several generic type parameters, which should be set to the various types defined in the object model we created in the previous step.

We will revisit the data context once we have finished configuring the objects required to customize the model; however, be aware that this is where we will implement the fluent mapping.

Step 3: Create a custom user store

In ASP.NET Identity 2.0 user stores are the repositories for user data. The Entity Framework implementation of the user store requires a data context. Here is the implementation of our custom user store:

public class ApplicationUserStore :
    UserStore<applicationuser, applicationrole,="" string,="" applicationuserlogin,="" applicationuserrole,="" applicationuserclaim="">,
    IUserStore,
   IDisposable
{
    public ApplicationUserStore(ApplicationDbContext context) : base(context) { }
}

Step 4: Modify ApplicationUserManager to use the new object model

There are several lines in the ApplicationUserManager (included in the default project template) that must be modified. First, in the static Create() method, modify the creation of the ApplicationUserManager so that it takes an ApplicationUserStore and ApplicationDbContext as arguments in its constructor, as such:

        var manager = new ApplicationUserManager(new ApplicationUserStore(context.Get()));

Step 5: Create the fluent mapping

We are finally ready to map our objects to our new data model. Begin by overriding OnModelCreating() in ApplicationDbContext . We will use EF Fluent API to map each of the five objects in our security object model to new tables in a new schema. The full fluent API mapping is included below:

        protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
        {
            modelBuilder.HasDefaultSchema("NAM");             modelBuilder.Entity().Map(c =>
            {
                c.ToTable("UserLogin");
                c.Properties(p => new
                {
                    p.UserId,
                    p.LoginProvider,
                    p.ProviderKey
                });
            }).HasKey(p => new { p.LoginProvider, p.ProviderKey, p.UserId });             // Mapping for ApiRole
            modelBuilder.Entity().Map(c =>
            {
                c.ToTable("Role");
                c.Property(p => p.Id).HasColumnName("RoleId");
                c.Properties(p => new
                {
                    p.Name
                });
            }).HasKey(p => p.Id);
            modelBuilder.Entity().HasMany(c => c.Users).WithRequired().HasForeignKey(c => c.RoleId);
            
            modelBuilder.Entity().Map(c =>
            {
                c.ToTable("User");
                c.Property(p => p.Id).HasColumnName("UserId");
                c.Properties(p => new
                {
                    p.AccessFailedCount,
                    p.Email,
                    p.EmailConfirmed,
                    p.PasswordHash,
                    p.PhoneNumber,
                    p.PhoneNumberConfirmed,
                    p.TwoFactorEnabled,
                    p.SecurityStamp,
                    p.LockoutEnabled,
                    p.LockoutEndDateUtc,
                    p.UserName
                });
            }).HasKey(c => c.Id);
            modelBuilder.Entity().HasMany(c => c.Logins).WithOptional().HasForeignKey(c => c.UserId);
            modelBuilder.Entity().HasMany(c => c.Claims).WithOptional().HasForeignKey(c => c.UserId);
            modelBuilder.Entity().HasMany(c => c.Roles).WithRequired().HasForeignKey(c => c.UserId);             modelBuilder.Entity().Map(c =>
            {
                c.ToTable("UserRole");
                c.Properties(p => new
                {
                    p.UserId,
                    p.RoleId
                });
            })
            .HasKey(c => new { c.UserId, c.RoleId });             modelBuilder.Entity().Map(c =>
            {
                c.ToTable("UserClaim");
                c.Property(p => p.Id).HasColumnName("UserClaimId");
                c.Properties(p => new
                {
                    p.UserId,
                    p.ClaimValue,
                    p.ClaimType
                });
            }).HasKey(c => c.Id);
        }

You are now ready to build and run the project. As before, navigate to the login page and attempt to sign in, which will force the creation of the new data model. You should now see the model in the custom schema with the table names we declared in the fluent mapping.

In part two of this series we will add audit fields to some of the tables and change the primary key data types from GUIDs to integers.

 

Attachments

自定义 ASP.NET Identity Data Model with EF的更多相关文章

  1. ASP.NET MVC - 安全、身份认证、角色授权和ASP.NET Identity

    ASP.NET MVC - 安全.身份认证.角色授权和ASP.NET Identity ASP.NET MVC内置的认证特性 AuthorizeAttribute特性(System.Web.Mvc)( ...

  2. 【ASP.NET Identity系列教程(一)】ASP.NET Identity入门

    注:本文是[ASP.NET Identity系列教程]的第一篇.本系列教程详细.完整.深入地介绍了微软的ASP.NET Identity技术,描述了如何运用ASP.NET Identity实现应用程序 ...

  3. ASP.NET Identity 一 (转载)

    来源:http://www.cnblogs.com/r01cn/p/5194257.html 注:本文是[ASP.NET Identity系列教程]的第一篇.本系列教程详细.完整.深入地介绍了微软的A ...

  4. ASP.NET Identity系列教程-2【Identity入门】

    https://www.cnblogs.com/r01cn/p/5177708.html13 Identity入门 Identity is a new API from Microsoft to ma ...

  5. [转]Creating an Entity Framework Data Model for an ASP.NET MVC Application (1 of 10)

    本文转自:http://www.asp.net/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/creating-a ...

  6. 用于Simple.Data的ASP.NET Identity Provider

    今天推举的这篇文章,本意不是要推举文章的内容,而是据此介绍一下Simple.Data这个很有意思的类ORM工具. 现在大家在.NET开发中如果需要进行数据访问,那么基本都会使用一些ORM工具,比如微软 ...

  7. 【分分钟内搭建一个带用户系统的博客程序(一)用户系统】asp.net core的Identity真香,EF真香!

    不用不知道,一用香到爆. 老哥是个屌丝前端,但也想写点web应用耍一耍.之前弄过了NodeJs,也弄过JAVA,最近由于写游戏的原因用C#,索性上手一波asp.net core. 这篇博客记录的是,如 ...

  8. EF,ADO.NET Entity Data Model简要的笔记

    1. 新建一个项目,添加一个ADO.NET Entity Data Model的文件,此文件会生成所有的数据对象模型,如果是用vs2012生的话,在.Designer.cs里会出现“// Defaul ...

  9. How to: Supply Initial Data for the Entity Framework Data Model 如何:为EF数据模型提供初始数据

    After you have introduced a data model, you may need to have the application populate the database w ...

随机推荐

  1. MyOD 代码实现

    MyOD的代码实现 一.题目要求: 编写MyOD.java 用java MyOD XXX实现Linux下od -tx -tc XXX的功能 二.设计思路 OD命令详解: 因此,该题目所要实现的功能为以 ...

  2. 在Ubuntu中部署并测试HyperLedger Fabric 0.6

    最近开始研究区块链,对这个新兴的技术有了基本概念上的了解,所以打算基于一个开源项目做做实验.如果是做数字货币,那么比特币的源代码是最好的了,不过这算是区块链1.0吧,已经有很多改进的竞争币和山寨币出来 ...

  3. CISCO交换机-SNMP配置

    1.1     SNMP基础配置 router> enable 进入路由器是用户模式 router# conf terminal 进入路由器的全局配置模式 #snmp-server commun ...

  4. 十九、多文件上传(ajaxFileupload实现多文件上传功能)

    来源于https://www.jb51.net/article/128647.htm 打开google 搜索"ajaxFileupload' ‘多文件上传"可以搜到许许多多类似的, ...

  5. H5 20-属性选择器上

    20-属性选择器上 --> 我是段落1 我是段落2 我是段落3 我是段落4 我是段落5 <!DOCTYPE html> <html lang="en"> ...

  6. 字符串的查找KMP

    基本思想,当出现不匹配的时候,就知晓一部分文本内容(因为在匹配失败前已经发生匹配) P[0 ~ k-1] == P[j-k ~ j-1] //KMP #include<iostream> ...

  7. 006-筛选分类排序搜索查找Filter-Classificatio-Sort-Search-Find-Seek-Locate

    006-筛选分类排序搜索查找Filter-Classificatio-Sort-Search-Find-Seek-Locate https://www.cnblogs.com/delphixx/p/1 ...

  8. Alpha冲刺阶段评分发布

    一班 二班 三班  四班

  9. Minimal string CodeForces – 797C

    题目链接 题目难度: 1700rating 题目类型:string+贪心+STL 题目思路: 由于题目要求的最终结果是字典序最小的那个字符串,那么我们从贪心的从’a’开始查找字符串里是否存在,如果存在 ...

  10. MySql实现分页查询的SQL,mysql实现分页查询的sql语句

    一:分页需求: 客户端通过传递start(页码),limit(每页显示的条数)两个参数去分页查询数据库表中的数据,那我们知道MySql数据库提供了分页的函数limit m,n,但是该函数的用法和我们的 ...