主要是為了方便授課上講授 TDD.NET 如何應用 Mock 隔離測試的觀念,所以打算藉由 ASP.NET Core Identity 2.1 驗證與授權 (Authentication and Authorization)的機制併整合訂購系統 (核心邏輯/資料庫存取位於另一專案)的案例,來展示 單元測試 (Unit Test)搭配 Mock 隔離的程式碼範例。
另外為了測試資料庫方便可攜供學員可以直接使用,所以打算不再使用具名的 SQL Express 檔案 (連線字串問題,多個專案要指定絕對路徑,不方便複製),而只使用 SQL Express LocalDB (預設位於 C:\使用者\使用者帳號目錄內),然後再以 Code First Migration 方式與 Seed Data 方便初始建置資料庫表格與測試資料,這些留待後續系列文章再作說明。
本系列文章並非是完整的 Step by Step 教學文,而僅是一份實作筆記,主要記錄了實作過程中一些重點摘要。同時也提供了一份程式碼範本,供個人以及對相關議題有興趣的讀者參考。
程式碼範本以 Git 版控儲存於 Github 儲庫:kenming/aspdotnet-core-identyity-2dot1-practice-note 。
每一個階段會標注 Tag 標籤方便提取研究與切換版本。
先簡單說明下 ASP.NET Core Identity,它是微軟所提供被歸為 ASP.NET Web 端的一個「會員 (Membership)」系統,提供給應用系統開發人員方便具有登入 (Login)驗證名稱與密碼的機制。它很明顯是 Client/Server 的 2-tier 分層方式所開發的系統,但還好因為 Login 這類機制係屬於「非功能性 (Non Functional)」需求,所以也不至於會干涉到應用系統關於「功能性需求 (如處理訂購、追蹤訂購等系統功能)」的耦合 (coupling)。未來可以全部抽換掉 Identity 而不影響到應用系統的主結構 (當然還是要稍稍花一些整合設計的心思)。
個人仍覺得 ASP.NET Identity 即便到 2.1 版本,但安裝與設定程序仍嫌繁瑣,而且從 1.X、2.0 到 2.1,每一次的安裝與設定方式大都不一樣,預期後續版本仍會有持續的變動震盪。所以更顯然絕對不要撰寫與問題領域 (problem domain)相關的邏輯在該專案內,這點從個人後續提供的範例就可以看到如何避免。
本篇文章先著重在如何安裝 Core Identity 2.1,然後新增「Scaffold Identity Item」,並修改些預設的登入選項參數 (如密碼長度),然後執行預設的首頁 (index)並選擇註冊 (register)帳號並執行登入 (login)。
安裝與設定參考文件,主要有兩篇:
Prerequisite
- Visual Studio 2017 (15.7 or newer)。
- 安裝 .NET Core SDK 2.1 (視平台選擇對應安裝版本)。
新增專案
- 新增專案,範本選擇「ASP.NET Core Web 應用程式」。
- 在出現的對話框,注意要確實選擇「ASP.NET Core 2.1」,模板選擇「Web 應用程式 (Model-View-Controller)」。然後點擊「變更驗證」,選擇「個別使用者帳戶」。
- 預設出現的專案目錄結構參考如圖。與前版不同的是有一個 \Areas\Identity 目錄,後續需要自行透過如 Scaffold Identity Item 新增相關的頁面。
新增 Scaffold Identity Item
- 於「方案總管 (solution explore)」,右鍵點選「加入 (Add) → 加入 Scaffold Identity Item」,選擇「識別 (Identity)」並新增項目。
- 出現的對話框,勾選「覆蓋所有檔案」選項,「資料內容類別」欄位,選擇「ApplicaitonDBContext (TurtleStore.Web.Data)」。
- 瀏覽在 \Areas\Identity\Pages\Account 目錄,即會出現 Account 相關的頁面。
- 為了方便測試,可以設定讓密碼長度與檢查簡單些。參考這裡,主要新增下列「Startup.cs」類別 → 「ConfigureServices()」方法內容。
services.Configure(options =>;
{
// Password settings
options.Password.RequireDigit = false;
options.Password.RequiredLength = 4;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequireLowercase = false;
options.Password.RequiredUniqueChars = 4;
// Lockout settings
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
options.Lockout.MaxFailedAccessAttempts = 10;
options.Lockout.AllowedForNewUsers = true;
// User settings
options.User.RequireUniqueEmail = true;
});
services.ConfigureApplicationCookie(options =>
{
// Cookie settings
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
// If the LoginPath isn't set, ASP.NET Core defaults
// the path to /Account/Login.
options.LoginPath = "/Account/Login";
// If the AccessDeniedPath isn't set, ASP.NET Core defaults
// the path to /Account/AccessDenied.
options.AccessDeniedPath = "/Account/AccessDenied";
options.SlidingExpiration = true;
});
- 注意下也要更新下註冊頁面檢查密碼的約束 (constraint) 實作內容。類別位於 Account\Register.cshtml.cs。
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 4)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
資料庫更新與設定
- 可以更名位於專案目錄檔案「appsettings.json」內的資料庫名稱。本例將資料庫更名為「aspnet-TurtleStore.DB」。
- 透過「套件管理器主控台 ( package manager console)」更新資料庫:
PM> update-database
- 透過「伺服器總管 (server explorer)」新增資料庫連接。
- 可以觀察新增資料庫關於「Identity」的資料庫表格。