Asp.Net Core之Identity应用(下篇)

一、前言

在上篇中简单介绍了 Asp.Net Core 自带的 Identity,一个负责对用户的身份进行认证的框架,当我们按需选择这个框架作为管理和存储我们应用中的用户账号数据的时候,就会添加到自己的项目当中去。这个时候,默认情况我们会使用自带的数据模型,但是考虑到需求的情况,我们可以通过自定义的方式更新数据模型,来达到我们的需求。

二、初识

在上篇中我们完成了数据迁移加上项目的搭建,其中ApplicationDbContext是负责与Identity标识相关的用户,继承于IdentityDbContext上下文。当然了,我们发现根据这个上下文的扩展性,可以自定义用户数据,进行配置。

比如:自定义扩展的用户数据类来继承于IdentityUser类,更改用户数据模型属性,更改主键、更改表名列名等来满足我们的业务要求。

三、实践

接着上篇的WebIdentityDemoV3.1项目,将自定义用户数据添加到Identity DB,自定义扩展的用户数据类应继承IdentityUser类, 文件名为Areas / Identity / Data / {项目名称}User.cs。

3.1 表说明

这个就是我们要准备自定义的用户数据,本示例是直接继承于 「Asp.Net Core 自带的 Identity」的。

光从数据库表名上,我们就知道其中的含义了,就是用户角色管理。

数据说明:

_EFMigrationsHistory 是 Ef的迁移历史表。

AspNetUserClaimsAspNetRoleClaims是用户和角色的声明表,Claim在其中扮演者很重要的角色,甚至角色(Role)都被转换成了Claim,可以了解之前说到的认证授权模式。

AspNetUsersAspNetRolesAspNetUserRoles存储用户和角色信息。

AspNetUserTokens 用于外部验证的「Token」存储。

AspNetUserLogins  保留如 Google, Facebook, Twitter ,QQ等第三方登录的信息。

3.2 自定义模型

上下文用于通过两种方式配置模型:

  • 为泛型类型参数提供实体和键类型。

  • 重写 OnModelCreating 以修改这些类型的映射。

重写时 OnModelCreatingbase.OnModelCreating 应首先调用,然后调用重写配置。EF Core 通常具有用于配置的最后一个 wins 策略。例如,如果 ToTable 先使用一个表名称调用实体类型的方法,然后再使用另一个表名称再次调用该方法,则使用第二个调用中的表名。

3.3 自定义数据

这里以用户类进行举例说明:

3.3.1 自定义用户类

定义ApplicationUser类继承于IdentityUser用户数据类, 自定义类命名约定 {Application}User。

    public class ApplicationUser:IdentityUser{ /// <summary>/// 用户编号/// </summary>public string UserNo { get; set; }/// <summary>/// 真实姓名/// </summary>public string UserTrueName { get; set; }}

3.3.2 修改服务配置

将原来Startup文件中的ConfigureServices服务配置中的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 类型用作上下文的泛型参数

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options): base(options){}
}

3.3.4 数据迁移

#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

「效果如下:」

可以发现,有对应的自定义字段了。

3.3.5 更新替换

如果之前已经搭建好了项目,那么你需要将IdentityUser类改成自定义的ApplicationUser类。

更新 Pages/Shared/_LoginPartial ,并将替换 IdentityUserApplicationUser

@using Microsoft.AspNetCore.Identity
@using WebApp1.Areas.Identity.Data
@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager

具体的其他替换修改方法就不说明演示了。

3.4 更改主键类型

在创建数据库之后更改PK列的数据类型在许多数据库系统上都存在问题。更改PK通常涉及删除和重新创建表。「因此,在创建数据库时,应在初始迁移中指定PK类型」。下面是更改主键类型步骤:

3.4.1 更改表主键类型

这里以ApplicationUser类为例,修改相关代码

    // 用户表设置主键为Intpublic class ApplicationUser : IdentityUser<Guid>{/// <summary>/// 用户编号/// </summary>public string UserNo { get; set; }/// <summary>/// 真实姓名/// </summary>public string UserTrueName { get; set; }}

3.4.2 修改上下文

    public class ApplicationDbContext : IdentityDbContext<ApplicationUser, IdentityRole<Guid>, Guid>

3.4.3 修改服务配置

       services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true).AddEntityFrameworkStores<ApplicationDbContext>();

3.4.4 数据迁移

#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 

此时表的主键类型已修改完成,包括关系表的外键类型也同步更新了,

「效果如下:」  

3.5 更改表名和列名

3.5.1 更改表名

再更改表名之前,请先调用 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 ,请配置该类型而不是默认类型。

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 更改长度

某些类型的数据库列可以配置某些 方面 (例如, 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);}); 
}

3.5.4 数据迁移

#进行更新数据模型 ,添加迁移,转换成相应的数据库
PM> Add-Migration CreateIdentitySchema2 -c ApplicationDbContext -o Data/Migrations
PM> Update-Database CreateIdentitySchema2 

此时表的主键类型已修改完成,包括关系表的外键类型也同步更新了,

「效果如下:」

3.6 初始化数据库

在创建项目时候,我们可以提前做好初始化数据的准备,将数据作为种子处理迁移到创建的数据库中进行初始化操作。

3.6.1 创建文件

创建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();}}

配置添加自定义用户信息和身份。

3.6.2 调用方法

然后我们可以从主入口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();}

3.6.3 程序运行

输入 dotnet run /seed

3.6.4 效果

总结

  1. 本篇简单介绍了对Identity自定义用户以及表结构说明,以及根据自定义更改生成模型,并添加到示例项目当中。

  2. 后续会将此身份认证机制来应用到「IdentityServer4」中使用,进行用户角色管理存储操作。

  3. 如果有不对的或不理解的地方,希望大家可以多多指正,提出问题,一起讨论,不断学习,共同进步。

  4. 项目地址

https://github.com/i3yuan/AspNetIdentityDemo

附加

「Identity ASP.NET Core 中的模型自定义」

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/305289.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如果每一种语言都对应一种女生,你会喜欢哪一个?

这几天调试都很顺利&#xff0c;今天很意外的不要加班&#xff0c;哥几个看着窗外还是白天&#xff0c;还有点不适应。没想到哥几个突然开始YY&#xff1a;如果每种语言都对应一种女生&#xff0c;你会喜欢哪一个&#xff1f;程序猿寂寞起来&#xff0c;我自己都害怕。碍于人数…

asp.net core安全事项(下)

越权越权是非常严重的安全漏洞&#xff0c;通常状态是开发人员对请求的限制逻辑不严格导致的。如果系统中有角色的概念&#xff0c;越权可能出现不同角色间的越权和同角色间的越权。相同角色&#xff1a;A用户&#xff0c;B用户是相同的角色。A用户和B用户都可以调用 /photo/{i…

[导入]php 安全基础 第八章 共享主机 文件系统浏览

8.4. 文件系统浏览 除了能在共享服务器上读取任意文件之外&#xff0c;攻击者还能建立一个可以浏览文件系统的脚本。由于你的大多数敏感文件不会保存在网站主目录下&#xff0c;此类脚本一般用于找到你的源文件的所在位置。请看下例&#xff1a; <pre> <?php if (iss…

程序员的项目周期(表情包版)

0. 需求审评会议进行中1. 开发阶段进行中….2. 代码复查阶段3. 测试阶段….4. 需求突然要改….5. 项目上线

[导入]php 安全基础 附录B. 函数

附录B. 函数 在我写作本书的时候&#xff0c;http://php.net/quickref.php列出了共3917个函数&#xff0c;其中包括一些类似函数的语法结构&#xff0c;在此我不准备把它们从函数中区分开来&#xff0c;而是把它作为函数看待。 由于函数数量很大&#xff0c;一一说明它们的正确…

6段Python代码刻画深度学习历史:从最小二乘法到深度神经网络

最小二乘法深度学习的一切都起源于这个数学片段&#xff08;我把它用Python 写了出来&#xff09;&#xff1a;这一方法是 1805 年巴黎数学家阿德利昂玛利埃勒让德首次提出的&#xff08;1805&#xff0c;Legendre&#xff09;&#xff0c;勒让德建立了许多重要的定理&#xff…

win7美化_Potplayer64位美化版,无棒子的tv推送

potplayer 64位是一款视频播放器&#xff0c;potplayer 64位目前正在新功能全力开发中&#xff0c;由于采用delphi编译程序kmplayer的一些弊端&#xff0c;姜龙喜先生为改进播放器本身的一些性能而重新用vc进行构架&#xff0c;有需要的伙伴们可以移步简易下载站获取&#xff0…

如何在 C# 8 中使用 Channels

在面对 生产者-消费者 的场景下&#xff0c; netcore 提供了一个新的命名空间 System.Threading.Channels 来帮助我们更高效的处理此类问题&#xff0c;有了这个 Channels 存在, 生产者 和 消费者 可以各自处理自己的任务而不相互干扰&#xff0c;有利于两方的并发处理&#x…

mockito mock void方法_使用 Junit + Mockito 实践单元测试!

一、前言相信做过开发的同学&#xff0c;都多多少少写过下面的代码&#xff0c;很长一段时间我一直以为这就是单元测试...SpringBootTestRunWith(SpringRunner.class)public class UnitTest1 {Autowiredprivate UnitService unitService;Testpublic void test() {System.out.pr…

人为什么会出轨?麻省理工学院告诉你:男女配对的真相

该实验出自麻省理工学院著名经济学家Dan Ariely的《The Upside of Irrationality》。结果很有趣&#xff0c;在我们的生活中也尤为常见。实验人员找来100位正值青春年华的大学生&#xff0c;男女各半。然后制作了100张卡片&#xff0c;卡片上写了从1到100总共一百个数字。单数的…

当 .NET 5 遇上OpenTelemetry,会碰撞出怎样的火花?

OpenTelemetry 介绍我在之前的几篇文章都介绍了 OpenTelemetry, 你可以在这里找到OpenTelemetry - 云原生下可观测性的新标准深入研究.NET 5的开放式遥测OpenTelemetry是谷歌和微软共同推进的云原生监控的新规范&#xff0c; 兼容OpenTracing和OpenCensusOpenTelemetry的终极目…

kotlin中mainactivity无法直接调用xml中的控件_使用52North 客户端接口调用OGC WPS服务...

52North是一个来自研究机构、工业界和公共行政管理界的研究者组成的开放国际合作组织&#xff0c;他们通过协作研发流程促进地理信息学创新。具体来说他们开发新的地理信息概念和技术&#xff0c;例如用于管理时空测量数据&#xff0c;以及通过网络共享地理处理技术。他们评估新…

明天放假,我放价!一个国庆假期教你学会数学建模

原价298元&#xff0c;国庆放价&#xff01;248元即可报名学习&#xff01;数学建模涉及的内容比较广泛&#xff0c;比如碎纸片问题中所涉及的图像识别及神经网络、小区开放问题中所涉及的车流模拟仿真、还有“互联网”时代的出租车资源配置中所涉及的运筹调度。或许数学建模的…

微软开源可扩展存储引擎Extensible Storage Engine

喜欢就关注我们吧&#xff01;昨日&#xff0c;微软副总裁 Scott Van Vliet 在推特上表示&#xff0c;可扩展存储引擎 Extensible Storage Engine&#xff08;ESE&#xff09;现已开源。可扩展存储引擎 Extensible Storage Engine&#xff08;ESE&#xff0c;也称 JET Blue&…

.NET应用程序中异步调用Web Service的几种方法 come from: veryhappy(wx.net)

测试程序界面 图一&#xff0c;调用前界面 图二&#xff0c;调用后界面 详细代码实现 闲言少叙&#xff0c;直接进入主题吧。首先一个声明一个类&#xff08;将来在客户端与服务器间传递&#xff09;&#xff1a; public classClass1 { private int _ID; priv…

完美国际真数苹果_如果给你推荐一款很贵,但好用的苹果手机壳,你会买吗?...

【引言】说到全球最热门的手机&#xff0c;大家都知道一定是iPhone啦&#xff0c;作为系统和功能整合得最优秀的手机&#xff0c;不足的地方也非常明显&#xff0c;比如外壳不耐剐蹭&#xff0c;维修成本很高......&#xff0c;所以大多数果粉都会选择保护壳或者贴膜来保护自己…

使用缓存防击穿,解决微信”被动回复用户消息”重试回复问题

背景做微信公众号开发的时候&#xff0c;其中有个接收普通消息、接收事件推送 API。有这么条规则&#xff0c; ”微信服务器在五秒内收不到响应会断掉连接&#xff0c;并且重新发起请求&#xff0c;总共重试三次。假如服务器无法保证在五秒内处理并回复&#xff0c;可以直接回…

美国硅谷预测10年后的世界,再不懂你就落伍了

预测毕竟是预测&#xff0c;不一定会全部都会实现&#xff0c;但其中相当多的一部分将会成为我们生活中的现实。生活在信息社会的每一个人&#xff0c;都应该对这些发展趋势有所了解&#xff0c;特此推荐给我们的读者朋友。现在因为人工智能(AI)的发展&#xff0c;配合更高速度…

谷歌浏览器安卓_安卓免费时代结束,国产手机或将集体涨价?

天下没有免费的午餐&#xff0c;免费多年的谷歌安卓系统或许即将成为历史。昨天上午&#xff0c;有网友发现&#xff0c;安卓官方推特账号发布推文&#xff0c;宣称公司计划在今年第三季度向中国手机厂商收取费用&#xff0c;包括华为、中兴、小米等。尽管这条消息又被秒删&…