快速掌握 ASP.NET 身份认证框架 Identity - 用户注册

推荐关注「码侠江湖」星标,时刻不忘江湖事

这是 ASP.NET Core Identity 系列的第二篇文章,上一篇文章介绍了 Identity 框架的集成,以及一些基础知识。

这篇文章讲一讲如何在 ASP.NET Core Identity 中实现用户注册。

点击上方或后方蓝字,阅读 ASP.NET Core Identity 系列合集。

本篇文章的示例项目:https://github.com/zilor-net/IdentitySample/tree/main/Sample02

46acd8c7757979144a8f344273565dee.png

准备工作

ASP.NET Core Identity 提供了很多不同的身份选项,帮助我们实现用户注册。

首先,让我们在 「Models」 文件夹中,创建一个用户注册模型:

public class UserRegistrationModel
{[Display(Name = "姓氏")]public string FirstName { get; set; }[Display(Name = "名字")]public string LastName { get; set; }[Display(Name = "电子邮箱")][Required(ErrorMessage = "电子邮箱不能为空")][EmailAddress]public string Email { get; set; }[Display(Name = "密码")][Required(ErrorMessage = "密码不能为空")][DataType(DataType.Password)]public string Password { get; set; }[Display(Name = "确认密码")][DataType(DataType.Password)][Compare("Password", ErrorMessage = "密码与确认密码不匹配。")]public string ConfirmPassword { get; set; }
}

这个类中的属性,需要用户在注册表单中填写。

其中,EmailPassword 属性是必需的,ConfirmPassword 属性的值必须与 Password 属性的值匹配。

有了这个模型,我们再来创建一个 「Account」 控制器:

public class AccountController : Controller
{[HttpGet]public IActionResult Register(){return View();}[HttpPost][ValidateAntiForgeryToken]public IActionResult Register(UserRegistrationModel userModel){return View();}
}

它有两个 Register 操作方法,用来提供用户注册功能。

第一个 Register 方法接受 Get 请求,用来显示注册表单的视图;

第二个 Register 方法接受 Post 请求,用来处理用户注册逻辑,并显示注册结果的视图。

还需要为 GET Register 操作,创建一个视图,这里我们可以直接使用 Create 模板,模型类选择 UserRegistrationModel 类即可。

5a8f805151b658c18bcc9cf63938bb4c.png

现在这个视图中的表单,已经可以为用户注册模型,提供所有的输入字段了。

需要注意的是,我们最好修改表单中 asp-validation-summary 的值为 All

因为,默认情况下,它只能显示模型验证产生的错误信息,而不会显示我们自己设置的验证错误。

视图中的 Create 按钮,会跳转到 POST 请求的 Register 操作方法,并且填充用户注册模型。

在 Web API 中使用来自用户的数据,最好采用数据传输对象的方式,但是在 MVC 中不一定如此。

这是因为 MVC 有模型的存在,在有视图的情况下,模型在一定程度上,替代了数据传输对象职责。

由于我们的数据通过视图传递,因此该类模型也被称为视图模型。

「UserRegistrationModel」 就是一个视图模型,如果我们想要真正的在数据库中存储它,必须要把它映射到 User 实体类。

我们需要安装 AutoMapper :

Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection

然后,在 Program 类中注册它:

builder.Services.AddAutoMapper(Assembly.GetExecutingAssembly());

接着,在布局页的导航菜单上,添加一个注册按钮。

因为后面还要添加登录按钮,所以为了代码的可维护性,我们可以创建一个分部视图:

// Shared\_LoginPartial.cshtml<ul class="navbar-nav"><li class="nav-item"><a class="nav-link text-dark" asp-controller="Account" asp-action="Register">注册</a>    </li>
</ul>

最后,修改 「_Layout.cshtml」 布局视图,在导航菜单上添加登录分布视图:

<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse"><partial name="_LoginPartial" /><!-- 添加 --><ul class="navbar-nav flex-grow-1">

注册操作

准备工作都已经完成了。

现在,让我们从用户注册逻辑开始。

首先,必须在 「Account」 控制器中,注入 AutoMapperUserManager 类:

private readonly IMapper _mapper;
private readonly UserManager<User> _userManager;
public AccountController(IMapper mapper, UserManager<User> userManager)
{_mapper = mapper;_userManager = userManager;
}

「UserManager」 由 Identity 框架提供,它负责帮助我们管理应用程序中的用户。

用户注册逻辑在 Post 请求的 Register 方法中实现:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(UserRegistrationModel userModel)
{if(!ModelState.IsValid){return View(userModel);}var user = _mapper.Map<User>(userModel);var result = await _userManager.CreateAsync(user, userModel.Password);if(!result.Succeeded){foreach (var error in result.Errors){ModelState.TryAddModelError(error.Code, error.Description);}return View(userModel);}await _userManager.AddToRoleAsync(user, "Guest");return RedirectToAction(nameof(HomeController.Index), "Home");
}

这里需要注意的是,我们把这个方法改成了异步的,因为 ·UserManager· 的助手方法也是异步的。

在方法内部,先检查模型的有效性,如果它是无效的,就返回带有无效模型的相同视图。

如果检查通过,就将 userModel 射到 user 实体。

使用 CreateAsync 方法用来注册用户,它会对密码进行哈希后保存。

之后,检查它返回的创建结果。

如果创建成功,我们只需在 UserManager 的帮助下,使用 AddToRoleAsync 方法,给用户添加一个默认的角色,并将用户重定向到 Index 页面。

但是如果注册失败,就遍历所有的错误,并将它们添加到 ModelState 中。

前面我们已经将视图的验证信息摘要改为了 All,否则这里添加的错误,不会显示出来。

最后,不要忘记创建 AutoMapper 的映射配置类:

// MappingProfile.cspublic class MappingProfile : Profile
{public MappingProfile(){CreateMap<UserRegistrationModel, User>().ForMember(user => user.UserName, expression => expression.MapFrom(userModel => userModel.Email));}
}

这里我们把电子邮件映射到用户名,因为我们在注册表单中没有提供用户名的字段。

现在启动应用,测试一下用户注册。

我可以尝试各种错误的注册内容,观察验证结果。

需要注意的是,默认的密码验证规则,非常的复杂,它不但要求有大小写字母,还必须要求你有一个特殊符号。

这个密码规则很不错,但是有时候我可能并不需要强规则。

而且我们使用了电子邮件作为用户名,但是默认情况下,没有要求电子邮件是唯一的。

所以,我们可以改变这些规则,这需要在注册 Identity 的地方,通过配置选项修改:

services.AddIdentity<User, IdentityRole>(options =>{options.Password.RequiredLength = 6;options.Password.RequireDigit = false;options.Password.RequireUppercase = false;options.Password.RequireNonAlphanumeric = false;options.Password.RequireLowercase = false;options.User.RequireUniqueEmail = true;})
.AddEntityFrameworkStores<ApplicationContext>();

比如,我们这里取消了数字、大写字母和特殊字符的验证,最小长度改为 6 位,同时设置电子邮件的唯一验证。

现在我们再来启动应用,测试一下注册过程,比如错误的密码格式、重复的电子邮箱。

大家通过一些测试可以发现,有些错误信息是中文的、有些则是英文的。

因为这个错误分为两种类型,一种是我们自定义的模型验证错误,我们已经设置了错误的信息,所以这种类型是中文的。

另一种是 ASP.NET Core Identity 内置的验证错误,它是我们通过在操作方法中,自己读取并添加进模型状态的。

因为 ASP.NET Core Identity 是英文版的,所以我们获取到的是英文信息,

不过,我们也可以自行定义中文信息,这需要我们创建一个自定义的错误描述类:

public class CustomIdentityErrorDescriber : IdentityErrorDescriber
{public override IdentityError PasswordTooShort(int length){return new(){Code = nameof(PasswordTooShort),Description = $"密码至少需要 {length} 位"};}public override IdentityError DuplicateEmail(string email){return new(){Code = nameof(DuplicateUserName), Description = $"电子邮箱 {email} 已存在。"};}public override IdentityError DuplicateUserName(string username){return new(){Code = nameof(DuplicateUserName), Description = $"用户名 {username} 已存在。"};}

自定义的错误信息,需要通过覆写 「IdentityErrorDescriber」 基类的错误方法,设置你想要的错误描述。

需要的话,你可以通过阅读源码,找到所有的错误方法。

我们还需要把它配置到注册 Identity 服务的方法中:

AddErrorDescriber<CustomIdentityErrorDescriber>()

小结

现在,我们已经实现了用户注册,具体的代码可以参看示例项目,下篇文章将会继续讲解用户登陆以及身份认证。

更多精彩内容,请关注我▼▼

5bc5756b77a8671cb9d5d29913cf1172.gif

如果喜欢我的文章,那么

在看和转发是对我最大的支持!

(戳下面蓝字阅读)

d07925ccd5e268e0814287d660691a6c.png

推荐关注微信公众号:码侠江湖

                        8b2e3e41862831cde44bda4b32836e69.png觉得不错,点个在看再走哟

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

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

相关文章

Android命令Monkey压力测试,详解

支持原创&#xff0c;前半部分来源博客原文&#xff1a;http://blog.csdn.net/huangbiao86/article/details/8490743shell, monkey, system, Android, 文件系统Monkey, 示例, 简介一、Monkey测试简介Monkey测试是Android平台自动化测试的一种手段&#xff0c;通过Monkey程序模拟…

JAVA 排序工具类

提供了以下排序&#xff1a; 冒泡排序选择排序插入排序希尔排序快速排序归并排序桶排序堆排序package com.xingej.algorithm.sort;import java.util.ArrayList; import java.util.Collections;/*** 排序工具类* * author erjun 2017年12月13日 上午8:38:22*/public class SortU…

js中null,undefined,false,0,'',[],{}判断方法

目录 1.数据类型 2.JSON字符串 3.数字类型 4.非的布尔值 5.与非比较 一、单独判断 1.null 2.undefined 3.0 4.“” 5.判断undefined、null与NaN: 因为获取到数据的不确定性&#xff0c;常常会导致一些异常情况&#xff0c;使得页面报错&#xff0c;往往要兼容这些异…

【GIS风暴】30米分辨率地表覆盖数据GlobeLand30原始数据集简介及下载地址

数据集预览&#xff1a; GlobeLand30是30米空间分辨率全球地表覆盖数据&#xff0c;目前可供下载使用的有3年的数据&#xff1a;2000-2010-2020&#xff0c;本文主要讲述GlobeLand30的官网下载地址和数据集简介。 数据处理方法、成果数据下载&#xff1a; 【ArcGIS风暴】ArcGI…

Git之解决git stash pop多次产生的文件冲突问题

1、问题 我们用git命令一般拉取线上代码的时候&#xff0c;本地修改了&#xff0c;我们一般先git stash下&#xff0c;接下来git pull, 然后git stash pop下&#xff0c;但是我新增了文件&#xff0c;没有添加到本地git(也就是没有git add file这个新增加的文件)&#xff0c;然…

记一次意外

今天尝试给同一个对象绑定多个事件: document.getElementById("a").οnfοcus function(){ alert("1") }.οnclick function(){ alert("2") } 发现弹出2&#xff0c;改变focus和click的顺序后依旧如此&…

一、基础折线图详解《手把手教你 ECharts 数据可视化详解》

注&#xff1a;本系列教程需要对应 JavaScript 、html、css 基础&#xff0c;否则将会导致阅读时困难&#xff0c;本教程将会从 ECharts 的官方示例出发&#xff0c;详解每一个示例实现&#xff0c;从中学习 ECharts 。 ECharts 官方示例&#xff1a;https://echarts.apache.o…

NLog自定义Target之MQTT

NLog是.Net中最流行的日志记录开源项目(之一)&#xff0c;它灵活、免费、开源官方支持文件、网络(TCP、UDP)、数据库、控制台等输出社区支持Elastic、Seq等日志平台输出实时日志需求在工业物联网等特定场景下需要实时获取日志信息工业物联网领域常用的是mqtt协议那我们就使用NL…

2016-1-27

2019独角兽企业重金招聘Python工程师标准>>> 1.前端的三大技能:1.1.描述网页内容html 1.2.描述网页样式css 1.3.描述网页行为js2.html和jsp区别在于静态和动态..bootsharp是目前比较火爆的css..angular是目前比较火爆的js.3.单点登陆(SSO):登陆一次就可以访问所有相…

【ArcGIS风暴】ArcGIS生成GlobeLand30土地利用数据集中国区域行列号shp格式对照图(附shp下载)

效果预览: 本文主要讲述了在ArcGIS中生成GlobeLand中国区域对照行列号的shp格式矢量数据,用途在于将自己的研究区跟行列号矢量图层直接叠加显示,快速找出自己所需要的图幅号,便于快速下载数据。同时为了方便使用,本文提供了对照图的下载。 文章目录 1. 创建文件数据库2. 创…

Android 节操视频播放器jiecaovideoplayer自定义播放音频使用:屏蔽全屏按钮,增加倒计时,当前时间/总时间

一、屏蔽全屏按钮 找到JCVideoPlayerStandard.java文件中的代码&#xff1a; private void fixAudio() {if (SrcType.equalsIgnoreCase("Audio")) {//如果是音频&#xff0c;始终显示coverImageView//thumbImageView.setVisibility(View.VISIBLE);coverImageView.se…

Android之Dialog提示Unable to add window -- token is not valid; is your activity running?

1、问题 Dialog奔溃提示Unable to add window -- token android.os.BinderProxy@b251dbc is not valid; is your activity running? 2、解决办法 传递context到dialog的时候,要记得先判断状态是不是isFinishing或者isDestroyed状态,这个时候就不要再去show相关的dialog了,…

nagios监控haproxy(借助脚本)

nagios监控haproxy&#xff08;借助脚本&#xff09; 修改后的脚本如下&#xff08;需添加指示灯的状态&#xff09; # vi haproxy.sh #!/bin/bash Portnetstat -ntpl | grep haproxy | awk -F[:" "] {print $5} if [ $Port "1080" ];then echo "OK …

一、Qt初尝试,做一个QT计算器《QT 入门到实战》

学习目标 了解 qt 的基本信息了解 qt 的下载及安装了解创建一个基本 qt 项目的流程了解信号与槽通过示例了解信号与槽的设置与编写了解控件添加的方式了解控件如何使用代码获取其文本了解控件如何使用代码设置其文本使用 connect 自定义信号与槽了解使用样式修饰控件外观了解使…

VS C#语言获取输入名称的汉语拼音简拼码和全拼码完整案例教程

结果预览: 扩展阅读: SQL语言获取拼音码:SQL Server编写函数获取汉字的拼音码(简拼) 文章目录 1. 拼音码类编写2. 界面设计3. 前端调用4. 结果展示1. 拼音码类编写 打开Visual Studio,新建一个Winform项目,再添加一个类文件,命名为PYM。 键入如下代码: using Syst…

iOS duplicate symbol for architecture arm64 解决办法

导致这个问题的原因有多种&#xff1a; 1.重复定义了const常量。 2.多个第三方库同时用到了某个函数库。 暂时列举这几种&#xff0c;以后遇到了其他原因再加。转载于:https://www.cnblogs.com/zhanglinfeng/p/5987077.html

WPF 实现星空效果

本文经原作者授权以原创方式二次分享&#xff0c;欢迎转载、分享。原文作者&#xff1a;普通的地球人原文地址&#xff1a;https://www.cnblogs.com/tsliwei/p/6282183.htmlGithub地址&#xff1a;https://github.com/WPFDevelopersOrg/WPFDevelopers效果前阵子看到ay的蜘蛛网效…

data类型的Url的格式

data类型的Url的格式 一、data类型的简介 所谓"data"类型的Url格式&#xff0c;是在RFC2397中提出的&#xff0c;目的对于一些“小”的数据&#xff0c;可以在网页中直接嵌入&#xff0c;而不是从外部文件载入。例如对于img这个Tag&#xff0c;哪怕 这个图片非常非…

C语言试题八十之统计单词个数

📃个人主页:个人主页 🔥系列专栏:C语言试题200例目录 💬推荐一款刷算法、笔试、面经、拿大公司offer神器 👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 终端输入一…

SSIS 执行变量中的脚步输出列顺序与SQL查询列顺序不同

这个问题是朋友遇到的&#xff0c;做一个SSIS的程序将数据导入到txt。然后再用Oracle的工具导入到Oracle。但是在SSIS中执行变量脚步的时候&#xff0c;发现输出的列名称跟查询的列名称完全不同。比如Schema_id在查询的第三列&#xff0c;但是输出的时候到了第6列。 如图&#…