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. web 项目:解决插入 MySQL 数据库时中文乱码问题

    背景:在做 javaweb 项目的时,前台传递的中文最后插入数据库的时候总是出现乱码现象. 解决方案 ​ A.不管是使用 Idea.eclipse,确定自己的项目所使用的字符集是 UTF-8. ​ B ...

  2. Vue2.x源码学习笔记-从一个小例子查看vm实例生命周期

    学习任何一门框架,都不可能一股脑儿的从入口代码从上到下,把代码看完, 这样其实是很枯燥的,我想也很少有人这么干,或者这么干着干着可能干不下去了. 因为肯定很无聊. 我们先从一个最最简单的小例子,来查看 ...

  3. IIS7启动优化

    最近基于abp做的项目在发布到IIS后,第一次被访问异常缓慢,如果时间间隔久再去访问如第一次访问一般缓慢,为了解决这个问题对项目进行了一下系列操作: 1.优化js.css插件,插件分批加载,充分利用浏 ...

  4. Vue-比较方法、计算属性和侦听器

    分别用方法.计算属性和侦听器实现当fristName和lastName改变时,fullName跟着改变. 一.方法: html: <div id="app"> {{fu ...

  5. MyBatis + MySQL返回插入成功后的主键id

    这是最近在实现perfect-ssm中的一个功能时碰到的一个小问题,觉得需要记录一下,向MySQL数据库中插入一条记录后,需要获取此条记录的id值,以生成对应的key值存入到redis中,id为自增i ...

  6. React 系列 - 写出优雅的路由

    前言 自前端框架风靡以来,路由一词在前端的热度与日俱增,他是几乎所有前端框架的核心功能点.不同于后端,前端的路由往往需要表达更多的业务功能,例如与菜单耦合.与标题耦合.与"面包屑" ...

  7. IT江湖--这个冬天注定横尸遍野

    今年江湖大事繁起,又至寒冬,冻的不仅是温度,更是人心. 这两天上班途中看到多个公众号和媒体发了很多 "XXX公司裁员50%" 等等诸如此类的文章,也真是撼动人心.寒冬,比以往来的更 ...

  8. Mysql绿色版安装和遇到的问题

    MySQL绿色版安装整套流程,http://www.cnblogs.com/LiuChunfu/p/6426918.html,按这个教程装完后,用cmd命令窗口也能登陆.但是用mysql-font登不 ...

  9. HDU - 4027 线段树减枝

    这题太坑了...满满的都是坑点 1号坑点:给定左右区间有可能是反的...因为题目上说x,y之间,但是没有说明x,y的大小关系(害我一直RE到怀疑人生) 2号坑点:开根号的和不等于和开根号(还好避开了) ...

  10. Vue $nextTick 原理

    使用场景 在进行获取数据后,需要对新视图进行下一步操作或者其他操作时,发现获取不到 DOM. 原因: 这里就涉及到 Vue 一个很重要的概念:异步更新队列(JS运行机制 . 事件循环). Vue 在观 ...