推薦關注「碼俠江湖」加星標,時刻不忘江湖事
這是 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.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>()
小結
現在,我們已經實現了用戶注冊,具體的代碼可以參看示例項目,下篇文章將會繼續講解用戶登陸以及身份認證。
更多精彩內容,請關注我▼▼
如果喜歡我的文章,那么
在看和轉發是對我最大的支持!
(戳下面藍字閱讀)
ASP.NET 6 中間件系列
?ASP.NET 6 身份認證框架 Identity 系列
查缺補漏系統學習 EF Core 6? 系列
推薦關注微信公眾號:碼俠江湖
? ? ? ? ? ? ? ? ? ? ? ??覺得不錯,點個在看再走喲