热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Asp.NetCore之Identity应用(下篇)

Asp.NetCore之Identity应用(下篇)-一、前言在上篇中简单介绍了Asp.NetCore自带的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
    { 
        /// 
        /// 用户编号
        /// 
        public string UserNo { get; set; }
        /// 
        /// 真实姓名
        /// 
        public string UserTrueName { get; set; }

    }

3.3.2 修改服务配置

将原来Startup文件中的ConfigureServices服务配置中的IdentityUser改成ApplicationUser

services.AddDefaultIdentity(optiOns=> options.SignIn.RequireCOnfirmedAccount= true)
                .AddEntityFrameworkStores();

改成:

services.AddDefaultIdentity(optiOns=> options.SignIn.RequireCOnfirmedAccount= true)
                .AddEntityFrameworkStores();

3.3.3 修改上下文

将原来ApplicationDbContext上下文继承于IdentityDbContext,改成IdentityDbContext

原来的

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

改成:

ApplicationUser 类型用作上下文的泛型参数

public class ApplicationDbContext : IdentityDbContext
{
    public ApplicationDbContext(DbContextOptions 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 SignInManager
@inject UserManager UserManager

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

3.4 更改主键类型

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

3.4.1 更改表主键类型

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

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

3.4.2 修改上下文

    public class ApplicationDbContext : IdentityDbContext, Guid>

3.4.3 修改服务配置

       services.AddDefaultIdentity(optiOns=> options.SignIn.RequireCOnfirmedAccount= true)
                .AddEntityFrameworkStores();

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(b =>
            {
                b.ToTable("TblUsers");
            });

            builder.Entity>(b =>
            {
                //定义主键
                b.HasKey(u => u.Id);
                b.ToTable("TblUserClaims");
            });

            builder.Entity>(b =>
            {
                b.HasKey(u => new { u.LoginProvider, u.ProviderKey });
                b.ToTable("TblUserLogins");
            });

            builder.Entity>(b =>
            {
                b.HasKey(u => new { u.UserId, u.LoginProvider, u.Name });
                b.ToTable("TblUserTokens");
            });

            builder.Entity>(b =>
            {
                b.HasKey(u => u.Id);
                b.ToTable("TblRoles");
            });

            builder.Entity>(b =>
            {
                b.HasKey(u => u.Id);
                b.ToTable("TblRoleClaims");
            });

            builder.Entity>(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(b =>
    {
         b.Property(e => e.PasswordHash).HasColumnName("Password");
    });
}

3.5.3 更改长度

某些类型的数据库列可以配置某些 方面 (例如, string 允许) 最大长度。

protected override void OnModelCreating(ModelBuilder builder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity(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().CreateScope())
            {
                var cOntext= scope.ServiceProvider.GetService();
                context.Database.Migrate();

                var userMgr = scope.ServiceProvider.GetRequiredService>();
                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. 项目地址

附加

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


推荐阅读
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • flowable工作流 流程变量_信也科技工作流平台的技术实践
    1背景随着公司业务发展及内部业务流程诉求的增长,目前信息化系统不能够很好满足期望,主要体现如下:目前OA流程引擎无法满足企业特定业务流程需求,且移动端体 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • C语言注释工具及快捷键,删除C语言注释工具的实现思路
    本文介绍了C语言中注释的两种方式以及注释的作用,提供了删除C语言注释的工具实现思路,并分享了C语言中注释的快捷键操作方法。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • Tomcat/Jetty为何选择扩展线程池而不是使用JDK原生线程池?
    本文探讨了Tomcat和Jetty选择扩展线程池而不是使用JDK原生线程池的原因。通过比较IO密集型任务和CPU密集型任务的特点,解释了为何Tomcat和Jetty需要扩展线程池来提高并发度和任务处理速度。同时,介绍了JDK原生线程池的工作流程。 ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • Linux如何安装Mongodb的详细步骤和注意事项
    本文介绍了Linux如何安装Mongodb的详细步骤和注意事项,同时介绍了Mongodb的特点和优势。Mongodb是一个开源的数据库,适用于各种规模的企业和各类应用程序。它具有灵活的数据模式和高性能的数据读写操作,能够提高企业的敏捷性和可扩展性。文章还提供了Mongodb的下载安装包地址。 ... [详细]
  • 数字账号安全与数据资产问题的研究及解决方案
    本文研究了数字账号安全与数据资产问题,并提出了解决方案。近期,大量QQ账号被盗事件引起了广泛关注。欺诈者对数字账号的价值认识超过了账号主人,因此他们不断攻击和盗用账号。然而,平台和账号主人对账号安全问题的态度不正确,只有用户自身意识到问题的严重性并采取行动,才能推动平台优先解决这些问题。本文旨在提醒用户关注账号安全,并呼吁平台承担起更多的责任。令牌云团队对此进行了长期深入的研究,并提出了相应的解决方案。 ... [详细]
  • web.py开发web 第八章 Formalchemy 服务端验证方法
    本文介绍了在web.py开发中使用Formalchemy进行服务端表单数据验证的方法。以User表单为例,详细说明了对各字段的验证要求,包括必填、长度限制、唯一性等。同时介绍了如何自定义验证方法来实现验证唯一性和两个密码是否相等的功能。该文提供了相关代码示例。 ... [详细]
author-avatar
静待花开0088
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有