Asp.Net Core之Identity应用(下篇)
一、前言
在上篇中簡(jiǎn)單介紹了 Asp.Net Core 自帶的 Identity,一個(gè)負(fù)責(zé)對(duì)用戶的身份進(jìn)行認(rèn)證的框架,當(dāng)我們按需選擇這個(gè)框架作為管理和存儲(chǔ)我們應(yīng)用中的用戶賬號(hào)數(shù)據(jù)的時(shí)候,就會(huì)添加到自己的項(xiàng)目當(dāng)中去。這個(gè)時(shí)候,默認(rèn)情況我們會(huì)使用自帶的數(shù)據(jù)模型,但是考慮到需求的情況,我們可以通過自定義的方式更新數(shù)據(jù)模型,來達(dá)到我們的需求。
二、初識(shí)
在上篇中我們完成了數(shù)據(jù)遷移加上項(xiàng)目的搭建,其中ApplicationDbContext是負(fù)責(zé)與Identity標(biāo)識(shí)相關(guān)的用戶,繼承于IdentityDbContext上下文。當(dāng)然了,我們發(fā)現(xiàn)根據(jù)這個(gè)上下文的擴(kuò)展性,可以自定義用戶數(shù)據(jù),進(jìn)行配置。
比如:自定義擴(kuò)展的用戶數(shù)據(jù)類來繼承于IdentityUser類,更改用戶數(shù)據(jù)模型屬性,更改主鍵、更改表名列名等來滿足我們的業(yè)務(wù)要求。
三、實(shí)踐
接著上篇的WebIdentityDemoV3.1項(xiàng)目,將自定義用戶數(shù)據(jù)添加到Identity DB,自定義擴(kuò)展的用戶數(shù)據(jù)類應(yīng)繼承IdentityUser類, 文件名為Areas / Identity / Data / {項(xiàng)目名稱}User.cs。
3.1 表說明
這個(gè)就是我們要準(zhǔn)備自定義的用戶數(shù)據(jù),本示例是直接繼承于 「Asp.Net Core 自帶的 Identity」的。
光從數(shù)據(jù)庫表名上,我們就知道其中的含義了,就是用戶角色管理。
數(shù)據(jù)說明:
_EFMigrationsHistory 是 Ef的遷移歷史表。
AspNetUserClaims、AspNetRoleClaims是用戶和角色的聲明表,Claim在其中扮演者很重要的角色,甚至角色(Role)都被轉(zhuǎn)換成了Claim,可以了解之前說到的認(rèn)證授權(quán)模式。
AspNetUsers、AspNetRoles和AspNetUserRoles存儲(chǔ)用戶和角色信息。
AspNetUserTokens 用于外部驗(yàn)證的「Token」存儲(chǔ)。
AspNetUserLogins ?保留如 Google, Facebook, Twitter ,QQ等第三方登錄的信息。
3.2 自定義模型
上下文用于通過兩種方式配置模型:
為泛型類型參數(shù)提供實(shí)體和鍵類型。
重寫 OnModelCreating 以修改這些類型的映射。
重寫時(shí) OnModelCreating , base.OnModelCreating 應(yīng)首先調(diào)用,然后調(diào)用重寫配置。EF Core 通常具有用于配置的最后一個(gè) wins 策略。例如,如果 ToTable 先使用一個(gè)表名稱調(diào)用實(shí)體類型的方法,然后再使用另一個(gè)表名稱再次調(diào)用該方法,則使用第二個(gè)調(diào)用中的表名。
3.3 自定義數(shù)據(jù)
這里以用戶類進(jìn)行舉例說明:
3.3.1 自定義用戶類
定義ApplicationUser類繼承于IdentityUser用戶數(shù)據(jù)類, 自定義類命名約定 {Application}User。
????public?class?ApplicationUser:IdentityUser{?///?<summary>///?用戶編號(hào)///?</summary>public?string?UserNo?{?get;?set;?}///?<summary>///?真實(shí)姓名///?</summary>public?string?UserTrueName?{?get;?set;?}}3.3.2 修改服務(wù)配置
將原來Startup文件中的ConfigureServices服務(wù)配置中的IdentityUser改成ApplicationUser
services.AddDefaultIdentity<IdentityUser>(options?=>?options.SignIn.RequireConfirmedAccount?=?true).AddEntityFrameworkStores<ApplicationDbContext>();改成:
services.AddDefaultIdentity<ApplicationUser>(options?=>?options.SignIn.RequireConfirmedAccount?=?true).AddEntityFrameworkStores<ApplicationDbContext>();3.3.3 修改上下文
將原來ApplicationDbContext上下文繼承于IdentityDbContext,改成IdentityDbContext<ApplicationUser>
「原來的」
public?class?ApplicationDbContext?:?IdentityDbContext {public?ApplicationDbContext(DbContextOptions<ApplicationDbContext>?options):?base(options){} }「改成:」
將 ApplicationUser 類型用作上下文的泛型參數(shù)
public?class?ApplicationDbContext?:?IdentityDbContext<ApplicationUser> {public?ApplicationDbContext(DbContextOptions<ApplicationDbContext>?options):?base(options){} }3.3.4 數(shù)據(jù)遷移
#1.存在數(shù)據(jù)庫則先刪除數(shù)據(jù)庫 # Drop-Database (PMC) 或 dotnet ef database drop ( .NET Core CLI) #2.確認(rèn)刪除數(shù)據(jù)庫后,刪除遷移 # Remove-Migration (PMC) 或 dotnet ef migrations remove ( .NET Core CLI) # 再進(jìn)行更新數(shù)據(jù)模型 ,添加遷移,轉(zhuǎn)換成相應(yīng)的數(shù)據(jù)庫 PM> Add-Migration CreateIdentitySchema2 -c ApplicationDbContext -o Data/Migrations PM> Update-Database CreateIdentitySchema2「效果如下:」
可以發(fā)現(xiàn),有對(duì)應(yīng)的自定義字段了。
3.3.5 更新替換
如果之前已經(jīng)搭建好了項(xiàng)目,那么你需要將IdentityUser類改成自定義的ApplicationUser類。
更新 Pages/Shared/_LoginPartial ,并將替換 IdentityUser 為 ApplicationUser :
@using?Microsoft.AspNetCore.Identity @using?WebApp1.Areas.Identity.Data @inject?SignInManager<ApplicationUser>?SignInManager @inject?UserManager<ApplicationUser>?UserManager ?具體的其他替換修改方法就不說明演示了。
?3.4 更改主鍵類型
在創(chuàng)建數(shù)據(jù)庫之后更改PK列的數(shù)據(jù)類型在許多數(shù)據(jù)庫系統(tǒng)上都存在問題。更改PK通常涉及刪除和重新創(chuàng)建表。「因此,在創(chuàng)建數(shù)據(jù)庫時(shí),應(yīng)在初始遷移中指定PK類型」。下面是更改主鍵類型步驟:
3.4.1 更改表主鍵類型
這里以ApplicationUser類為例,修改相關(guān)代碼
????//?用戶表設(shè)置主鍵為Intpublic?class?ApplicationUser?:?IdentityUser<Guid>{///?<summary>///?用戶編號(hào)///?</summary>public?string?UserNo?{?get;?set;?}///?<summary>///?真實(shí)姓名///?</summary>public?string?UserTrueName?{?get;?set;?}}3.4.2 修改上下文
????public?class?ApplicationDbContext?:?IdentityDbContext<ApplicationUser,?IdentityRole<Guid>,?Guid>3.4.3 修改服務(wù)配置
???????services.AddDefaultIdentity<ApplicationUser>(options?=>?options.SignIn.RequireConfirmedAccount?=?true).AddEntityFrameworkStores<ApplicationDbContext>();3.4.4 數(shù)據(jù)遷移
#1.存在數(shù)據(jù)庫則先刪除數(shù)據(jù)庫 # Drop-Database (PMC) 或 dotnet ef database drop ( .NET Core CLI) #2.確認(rèn)刪除數(shù)據(jù)庫后,刪除遷移 # Remove-Migration (PMC) 或 dotnet ef migrations remove ( .NET Core CLI) # 再進(jìn)行更新數(shù)據(jù)模型 ,添加遷移,轉(zhuǎn)換成相應(yīng)的數(shù)據(jù)庫 PM> Add-Migration CreateIdentitySchema2 -c ApplicationDbContext -o Data/Migrations PM> Update-Database CreateIdentitySchema2此時(shí)表的主鍵類型已修改完成,包括關(guān)系表的外鍵類型也同步更新了,
「效果如下:」
3.5 更改表名和列名
3.5.1 更改表名
再更改表名之前,請(qǐng)先調(diào)用 base.OnModelCreating 。然后,添加配置覆蓋默認(rèn)表名,同時(shí)定義主鍵。這里的示例以將默認(rèn)表名改為以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");});}}如果使用之類的應(yīng)用類型 ApplicationUser ,請(qǐng)配置該類型而不是默認(rèn)類型。
3.5.2 更改列名
下面的示例將更改某些列名,按需更改
protected?override?void?OnModelCreating(ModelBuilder?builder) {base.OnModelCreating(modelBuilder);modelBuilder.Entity<ApplicationUser>(b?=>{b.Property(e?=>?e.PasswordHash).HasColumnName("Password");}); }3.5.3 更改長(zhǎng)度
某些類型的數(shù)據(jù)庫列可以配置某些 方面 (例如, string 允許) 最大長(zhǎng)度。
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);});? }3.5.4 數(shù)據(jù)遷移
#進(jìn)行更新數(shù)據(jù)模型 ,添加遷移,轉(zhuǎn)換成相應(yīng)的數(shù)據(jù)庫 PM> Add-Migration CreateIdentitySchema2 -c ApplicationDbContext -o Data/Migrations PM> Update-Database CreateIdentitySchema2此時(shí)表的主鍵類型已修改完成,包括關(guān)系表的外鍵類型也同步更新了,
「效果如下:」
3.6 初始化數(shù)據(jù)庫
在創(chuàng)建項(xiàng)目時(shí)候,我們可以提前做好初始化數(shù)據(jù)的準(zhǔn)備,將數(shù)據(jù)作為種子處理遷移到創(chuàng)建的數(shù)據(jù)庫中進(jìn)行初始化操作。
3.6.1 創(chuàng)建文件
創(chuàng)建SeedData.cs文件,用于初始化基礎(chǔ)數(shù)據(jù):
????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();}}配置添加自定義用戶信息和身份。
3.6.2 調(diào)用方法
然后我們可以從主入口Main方法調(diào)用它:
????????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();}3.6.3 程序運(yùn)行
輸入 dotnet run /seed
3.6.4 效果
總結(jié)
本篇簡(jiǎn)單介紹了對(duì)Identity自定義用戶以及表結(jié)構(gòu)說明,以及根據(jù)自定義更改生成模型,并添加到示例項(xiàng)目當(dāng)中。
后續(xù)會(huì)將此身份認(rèn)證機(jī)制來應(yīng)用到「IdentityServer4」中使用,進(jìn)行用戶角色管理存儲(chǔ)操作。
如果有不對(duì)的或不理解的地方,希望大家可以多多指正,提出問題,一起討論,不斷學(xué)習(xí),共同進(jìn)步。
項(xiàng)目地址
https://github.com/i3yuan/AspNetIdentityDemo
附加
「Identity ASP.NET Core 中的模型自定義」
總結(jié)
以上是生活随笔為你收集整理的Asp.Net Core之Identity应用(下篇)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Docker查看应用的实际内存
- 下一篇: asp.net core安全事项(下)