当前位置:网站首页>快速掌握 ASP.NET 身份认证框架 Identity - 用户注册
快速掌握 ASP.NET 身份认证框架 Identity - 用户注册
2022-06-22 15:36:00 【dotNET跨平台】
推荐关注「码侠江湖」加星标,时刻不忘江湖事
这是 ASP.NET Core Identity 系列的第二篇文章,上一篇文章介绍了 Identity 框架的集成,以及一些基础知识。
这篇文章讲一讲如何在 ASP.NET Core Identity 中实现用户注册。
点击上方或后方蓝字,阅读 ASP.NET Core Identity 系列合集。
本篇文章的示例项目:https://github.com/zilor-net/IdentitySample/tree/main/Sample02

准备工作
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; }
}这个类中的属性,需要用户在注册表单中填写。
其中,Email 和 Password 属性是必需的,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 类即可。

现在这个视图中的表单,已经可以为用户注册模型,提供所有的输入字段了。
需要注意的是,我们最好修改表单中 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」 控制器中,注入 AutoMapper 和 UserManager 类:
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.cs
public 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>()小结
现在,我们已经实现了用户注册,具体的代码可以参看示例项目,下篇文章将会继续讲解用户登陆以及身份认证。
更多精彩内容,请关注我▼▼

如果喜欢我的文章,那么
在看和转发是对我最大的支持!
(戳下面蓝字阅读)
推荐关注微信公众号:码侠江湖
觉得不错,点个在看再走哟
边栏推荐
- Implementing factory mode using enumeration
- 调用cmd 进程通信
- 社会担当 广汽本田“梦想童行”倡导儿童道路交通安全
- On the closure function of Scala
- for.. of vs. for.. In statement
- Figure operation flow of HAMA BSP Model
- 数据库mysql 主从方案
- 同花顺怎么开户?网上开户安全么?
- uniapp微信小程序获取页面二维码(带有参数)
- LETV group payment system architecture sharing for processing 100000 high concurrent orders per second
猜你喜欢
![[pop up box 2 at the bottom of wechat applet package]](/img/31/266e6a1f4200347c9324ea37b78562.png)
[pop up box 2 at the bottom of wechat applet package]

In case of default import failure
![[C language] deeply analyze the relationship between pointer and array](/img/f3/432eeee17034033361e05dde67aac3.jpg)
[C language] deeply analyze the relationship between pointer and array

jMeter使用案例

linux系统维护篇:mysql8.0.13源码下载及安装之“傻瓜式”操作步骤(linux-centos6.8)亲测可用系列

Partage de l'architecture du système de paiement du Groupe letv pour traiter 100 000 commandes simultanées élevées par seconde

【进阶自动化测试第一步】1分钟带你了解自动化测试

STM32 ADC acquisition via DMA (HAL Library)

In the era of video explosion, who is supporting the high-speed operation of video ecological network?

UI自动化定位利器-xpath实战
随机推荐
How to use IDM to accelerate Baidu cloud
Linux system maintenance: mysql8.0.13 source code download and installation "fool" operation steps (Linux centos6.8) test available series
每秒处理10万高并发订单的乐视集团支付系统架构分享
In the era of video explosion, who is supporting the high-speed operation of video ecological network?
Scala for derivation: the ability to define a value in the first part of a for expression and use it in subsequent (outer) expressions
【微信小程序封装底部弹出框二】
Add a millennial sign to a number (amount in millennia)
vs2017 在调试状态不显示QString值的解决方法
Purchase guide - how to purchase a high-quality conference tablet, these aspects must be compared
Safari兼容性问题总结
Task scheduling design of collection system
从Application提交角度审视Executor
Simple understanding of asynchronous IO
新手必会的静态站点生成器——Gridsome
企业级软件开发新模式:低代码
[pop up box at the bottom of wechat applet package] I
Vhedt business development framework
variable
短视频源码开发,优质的短视频源码需要做好哪几点?
购买指南丨如何购买一台高质量会议平板,这几个方面一定要对比