原文:
ASP.NET Core 新增用户
上一章节我们实现了一个注册表单,但也留了一些东西还没完成,就是提交注册表单后的动作。使用 Identity 实现注册功能,但提交注册表单后,需要做的事情很多,比如与 Identity 框架进行交互,以确保用户有效,告诉 Identity 框架创建该用户
在本章节,我们将学习如何创建用户,如何与 Identity 框架进行交互,以确保用户有效,然后创建该用户,最后使用注册的进行登录操作
所有的这些事情,都与 Identity
框架的两个核心服务: UserManager 和 SignInManager 有关
我们需要将这两项服务注入我们的控制器 AccountController
,然后才能在创建用户或登录用户时调用相应的 API
首先在 AccountController
控制器中添加两个使用 User
范型的 SignInManager
和 UserManager
类型的私有变量,然后再创建一个构造函数,用于接收这两个类型的参数
private SignInManager_signManager; private UserManager _userManager; public AccountController(UserManager userManager, SignInManager signManager) { _userManager = userManager; _signManager = signManager; }
接下来在使用了 [HttpPost]
特性的 Signup
方法中检查和验证提交的数据是否有效,主要是通过检查 ModelState
是否有效
[HttpPost] public async TaskSignup(RegisterViewModel model) { if (ModelState.IsValid) { } return View(); }
如果 ModelState
有效,则使用 UserName
来创建一个 User
的实例,并使用 _userManager
异步保存用户名和密码。
- 如果保存成功,则使用
_signManager
直接登录然后跳回首页 - 如果保存失败,则告知用户,并让用户输入正确的数据
内容是不是很多,不过反应到代码上,就寥寥几行
[HttpPost] public async TaskSignup(RegisterViewModel model) { if (ModelState.IsValid) { var user = new User { UserName = model.Username }; var result = await _userManager.CreateAsync(user, model.Password); if (result.Succeeded) { await _signManager.SignInAsync(user, false); return RedirectToAction("Index", "Home"); } else { foreach (var error in result.Errors) { ModelState.AddModelError("", error.Description); } } } return View(); }
我们来详细看看这段代码
-
如果 ModelState 有效,则使用 UserName 来创建一个 User 的实例
-
但是我们并没有把密码和传递给
User
,因为User
并没有属性来保存明文密码,所以我们只能直接将密码传递给 Identity 框架,框架会自动哈希密码 -
为了使用 Identity 框架保存用户数据,我们使用
UserManager
的异步方法CreateAsync
,该方法接收用户名和明文密码,然后使用这些数据创建一个新的用户 -
异步方法
CreateAsync
会返回一个结构,告诉我们是成功创建了用户还是失败了,如果失败了,会返回一些失败的原因 -
如果结果是成功的,就登录刚刚创建帐户的用户,且使用 SignInManager 为该用户签名,最后将用户重定向回主页
-
如果结果不成功,则告诉用户为什么,将 UserManager 返回的错误结果迭代添加到 ModelState 中。然后视图中就可以使用标签助手 ( 如验证标签助手 ) 显示这些错误信息
-
ModelState.AddModelError
方法接收一个键值对参数,第一个参数为键,第二个参数为值,如果键是空的,那么就会把所有错误都放在一起 -
最后,因为我们使用了异步方法,所以返回结果必须也是异步的,需要使用
async Task<IActionResult>
最后,当然了,为了让程序能正常运行,我们还需要引入三个命名空间 System.ComponentModel.DataAnnotations
、System.Threading.Tasks
和 HelloWorld.Models
,然后删除 AccountController()
空的构造函数
所有这些修改完成后,AccountController.cs
的代码如下
using System;using Microsoft.AspNetCore.Mvc; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; using System.ComponentModel.DataAnnotations; using HelloWorld.Models; namespace HelloWorld.Controllers { public class AccountController : Controller { private SignInManager_signManager; private UserManager _userManager; public AccountController(UserManager userManager, SignInManager signManager) { _userManager = userManager; _signManager = signManager; } [HttpGet] public ViewResult Signup() { return View(); } [HttpPost] public async Task Signup(RegisterViewModel model) { if (ModelState.IsValid) { var user = new User { UserName = model.Username }; var result = await _userManager.CreateAsync(user, model.Password); if (result.Succeeded) { await _signManager.SignInAsync(user, false); return RedirectToAction("Index", "Home"); } else { foreach (var error in result.Errors) { ModelState.AddModelError("", error.Description); } } } return View(); } } public class RegisterViewModel { [Required, MaxLength(64)] public string Username { get; set; } [Required, DataType(DataType.Password)] public string Password { get; set; } [DataType(DataType.Password), Compare(nameof(Password))] public string ConfirmPassword { get; set; } } }
注册演示
现在,我们重启应用程序,刷新浏览器,来到注册界面,输入 yufei
和 aBc123@456
因为密码规则必须是 6 个字符以上且包含一个大写字母和小写字母,且必须包含一个非数组字母字符,所以如果不是这种格式则会报错,比如 123
则输出错误如下
注册成功后就会跳转到首页
如果使用 SQLite Studio 打开我们的 blogging.db
数据库,就可以看到我们刚刚创建的用户
本章到这里就已经结束了,我们已经实现了一个相对完整的注册功能,为啥说是相对完整呢?
- 缺少防恶意和机器注册机制,也就是应该让输入手机号和邮箱然后发送验证码
- 缺少验证码,这样可能导致频繁的刷接口注册
- 缺少已登录用户跳回首页机制