在上篇中简单介绍了 Asp.Net Core 自带的 Identity,一个负责对用户的身份进行认证的框架,当咱们按需选择这个框架做为管理和存储咱们应用中的用户帐号数据的时候,就会添加到本身的项目当中去。这个时候,默认状况咱们会使用自带的数据模型,可是考虑到需求的状况,咱们能够经过自定义的方式更新数据模型,来达到咱们的需求。html
在上篇中咱们完成了数据迁移加上项目的搭建,其中ApplicationDbContext
是负责与Identity
标识相关的用户,继承于IdentityDbContext
上下文。固然了,咱们发现根据这个上下文的扩展性,能够自定义用户数据,进行配置。git
好比:自定义扩展的用户数据类来继承于IdentityUser
类,更改用户数据模型属性,更改主键、更改表名列名等来知足咱们的业务要求。github
接着上篇的WebIdentityDemoV3.1项目,将自定义用户数据添加到Identity DB,自定义扩展的用户数据类应继承IdentityUser类, 文件名为Areas / Identity / Data / {项目名称}User.cs。shell
这个就是咱们要准备自定义的用户数据,本示例是直接继承于 Asp.Net Core 自带的 Identity的。数据库
光从数据库表名上,咱们就知道其中的含义了,就是用户角色管理。c#
数听说明:框架
_EFMigrationsHistory
是 Ef的迁移历史表。ide
AspNetUserClaims
、AspNetRoleClaims
是用户和角色的声明表,Claim在其中扮演者很重要的角色,甚至角色(Role)都被转换成了Claim,能够了解以前说到的认证受权模式。学习
AspNetUsers
、AspNetRoles
和AspNetUserRoles
存储用户和角色信息。ui
AspNetUserTokens
用于外部验证的Token存储。
AspNetUserLogins
保留如 Google, Facebook, Twitter ,QQ等第三方登陆的信息。
上下文用于经过两种方式配置模型:
OnModelCreating
以修改这些类型的映射。重写时 OnModelCreating
, base.OnModelCreating
应首先调用,而后调用重写配置。 EF Core 一般具备用于配置的最后一个 wins 策略。 例如,若是 ToTable
先使用一个表名称调用实体类型的方法,而后再使用另外一个表名称再次调用该方法,则使用第二个调用中的表名。
这里以用户类进行举例说明:
定义ApplicationUser
类继承于IdentityUser
用户数据类, 自定义类命名约定 {Application}User。
public class ApplicationUser:IdentityUser { /// <summary> /// 用户编号 /// </summary> public string UserNo { get; set; } /// <summary> /// 真实姓名 /// </summary> public string UserTrueName { get; set; } }
将原来Startup文件中的ConfigureServices
服务配置中的IdentityUser
改为ApplicationUser
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<ApplicationDbContext>();
改为:
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<ApplicationDbContext>();
将原来ApplicationDbContext
上下文继承于IdentityDbContext
,改为IdentityDbContext<ApplicationUser>
原来的
public class ApplicationDbContext : IdentityDbContext { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } }
改为:
将 ApplicationUser
类型用做上下文的泛型参数
public class ApplicationDbContext : IdentityDbContext<ApplicationUser> { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } }
#1.存在数据库则先删除数据库 # Drop-Database (PMC) 或 dotnet ef database drop ( .NET Core CLI) #2.确认删除数据库后,删除迁移 # Remove-Migration (PMC) 或 dotnet ef migrations remove ( .NET Core CLI) # 再进行更新数据模型 ,添加迁移,转换成相应的数据库 PM> Add-Migration CreateIdentitySchema2 -c ApplicationDbContext -o Data/Migrations PM> Update-Database CreateIdentitySchema2
效果以下:
能够发现,有对应的自定义字段了。
若是以前已经搭建好了项目,那么你须要将IdentityUser
类改为自定义的ApplicationUser
类。
更新 Pages/Shared/_LoginPartial ,并将替换 IdentityUser
为 ApplicationUser
:
@using Microsoft.AspNetCore.Identity @using WebApp1.Areas.Identity.Data @inject SignInManager<ApplicationUser> SignInManager @inject UserManager<ApplicationUser> UserManager
具体的其余替换修改方法就不说明演示了。
在建立数据库以后更改PK列的数据类型在许多数据库系统上都存在问题。更改PK一般涉及删除和从新建立表。所以,在建立数据库时,应在初始迁移中指定PK类型。下面是更改主键类型步骤:
这里以ApplicationUser
类为例,修改相关代码
// 用户表设置主键为Int public class ApplicationUser : IdentityUser<Guid> { /// <summary> /// 用户编号 /// </summary> public string UserNo { get; set; } /// <summary> /// 真实姓名 /// </summary> public string UserTrueName { get; set; } }
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, IdentityRole<Guid>, Guid>
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<ApplicationDbContext>();
#1.存在数据库则先删除数据库 # Drop-Database (PMC) 或 dotnet ef database drop ( .NET Core CLI) #2.确认删除数据库后,删除迁移 # Remove-Migration (PMC) 或 dotnet ef migrations remove ( .NET Core CLI) # 再进行更新数据模型 ,添加迁移,转换成相应的数据库 PM> Add-Migration CreateIdentitySchema2 -c ApplicationDbContext -o Data/Migrations PM> Update-Database CreateIdentitySchema2
此时表的主键类型已修改完成,包括关系表的外键类型也同步更新了,
效果以下:
再更改表名以前,请先调用 base.OnModelCreating
。而后,添加配置覆盖默认表名,同时定义主键。这里的示例以将默认表名改成以tbl
开头命名的表名
protected override void OnModelCreating(ModelBuilder builder) { var maxKeyLength = 256; base.OnModelCreating(builder); //自定义修改表名,以tbl命名开头 builder.Entity<ApplicationUser>(b => { b.ToTable("TblUsers"); }); builder.Entity<IdentityUserClaim<Guid>>(b => { //定义主键 b.HasKey(u => u.Id); b.ToTable("TblUserClaims"); }); builder.Entity<IdentityUserLogin<Guid>>(b => { b.HasKey(u => new { u.LoginProvider, u.ProviderKey }); b.ToTable("TblUserLogins"); }); builder.Entity<IdentityUserToken<Guid>>(b => { b.HasKey(u => new { u.UserId, u.LoginProvider, u.Name }); b.ToTable("TblUserTokens"); }); builder.Entity<IdentityRole<Guid>>(b => { b.HasKey(u => u.Id); b.ToTable("TblRoles"); }); builder.Entity<IdentityRoleClaim<Guid>>(b => { b.HasKey(u => u.Id); b.ToTable("TblRoleClaims"); }); builder.Entity<IdentityUserRole<Guid>>(b => { b.HasKey(u => new { u.UserId, u.RoleId }); b.ToTable("TblUserRoles"); }); } }
若是使用之类的应用类型 ApplicationUser
,请配置该类型而不是默认类型。
下面的示例将更改某些列名,按需更改
protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<ApplicationUser>(b => { b.Property(e => e.PasswordHash).HasColumnName("Password"); }); }
某些类型的数据库列能够配置某些 方面 (例如, string
容许) 最大长度。
protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<ApplicationUser>(b => { b.Property(u => u.UserName).HasMaxLength(128); b.Property(u => u.NormalizedUserName).HasMaxLength(128); b.Property(u => u.Email).HasMaxLength(128); b.Property(u => u.NormalizedEmail).HasMaxLength(128); }); }
#进行更新数据模型 ,添加迁移,转换成相应的数据库 PM> Add-Migration CreateIdentitySchema2 -c ApplicationDbContext -o Data/Migrations PM> Update-Database CreateIdentitySchema2
此时表的主键类型已修改完成,包括关系表的外键类型也同步更新了,
效果以下:
在建立项目时候,咱们能够提早作好初始化数据的准备,将数据做为种子处理迁移到建立的数据库中进行初始化操做。
建立SeedData.cs文件,用于初始化基础数据:
public class SeedData { public static void EnsureSeedData(IServiceProvider serviceProvider) { Console.WriteLine("Seeding database..."); using (var scope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope()) { var context = scope.ServiceProvider.GetService<ApplicationDbContext>(); context.Database.Migrate(); var userMgr = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>(); var alice = userMgr.FindByNameAsync("alice").Result; if (alice == null) { alice = new ApplicationUser { UserName = "alice" }; var result = userMgr.CreateAsync(alice, "Pass123$").Result; if (!result.Succeeded) { throw new Exception(result.Errors.First().Description); } result = userMgr.AddClaimsAsync(alice, new Claim[]{ new Claim(JwtClaimTypes.Name, "Alice Smith"), new Claim(JwtClaimTypes.GivenName, "Alice"), new Claim(JwtClaimTypes.FamilyName, "Smith"), new Claim(JwtClaimTypes.Email, "AliceSmith@email.com"), new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean), new Claim(JwtClaimTypes.WebSite, "http://alice.com") }).Result; if (!result.Succeeded) { throw new Exception(result.Errors.First().Description); } Console.WriteLine("alice created"); } else { Console.WriteLine("alice already exists"); } var bob = userMgr.FindByNameAsync("bob").Result; if (bob == null) { bob = new ApplicationUser { UserName = "bob" }; var result = userMgr.CreateAsync(bob, "Pass123$").Result; if (!result.Succeeded) { throw new Exception(result.Errors.First().Description); } result = userMgr.AddClaimsAsync(bob, new Claim[]{ new Claim(JwtClaimTypes.Name, "Bob Smith"), new Claim(JwtClaimTypes.GivenName, "Bob"), new Claim(JwtClaimTypes.FamilyName, "Smith"), new Claim(JwtClaimTypes.Email, "BobSmith@email.com"), new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean), new Claim(JwtClaimTypes.WebSite, "http://bob.com"), new Claim("location", "somewhere") }).Result; if (!result.Succeeded) { throw new Exception(result.Errors.First().Description); } Console.WriteLine("bob created"); } else { Console.WriteLine("bob already exists"); } } Console.WriteLine("Done seeding database."); Console.WriteLine(); } }
配置添加自定义用户信息和身份。
而后咱们能够从主入口Main
方法调用它:
public static void Main(string[] args) { var seed = args.Contains("/seed"); if (seed) { args = args.Except(new[] { "/seed" }).ToArray(); } var host = CreateHostBuilder(args).Build(); if (seed) { SeedData.EnsureSeedData(host.Services); } host.Run(); }
输入 dotnet run /seed
Identity
自定义用户以及表结构说明,以及根据自定义更改生成模型,并添加到示例项目当中。