康廷數位購物網 8 -認識 ASP.NET Identity 驗證授權機制

驗證與授權功能是所有購物網站必須具備的預設功能,因此 Visual Studio ASP.NET MVC 專案在預設的情形下,亦同時支援驗證授權功能,ASP.NET MVC 5 不同於之前的版本,內建的會員管理系統驗證機制由全新的ASP.NET Identity系統取代,提供更彈性且更廣泛的使用者身份管理支援 …

驗證與授權功能是所有購物網站必須具備的預設功能,因此 Visual Studio ASP.NET MVC 專案在預設的情形下,亦同時支援驗證授權功能,ASP.NET MVC 5 不同於之前的版本,內建的會員管理系統驗證機制由全新的ASP.NET Identity系統取代,提供更彈性且更廣泛的使用者身份管理支援。從這一篇開始,我們要分成幾篇針對相關機制的整合進行討論。 新增一個ASP.NET MVC 專案於專案建立設定畫面中,右下方有一個「變更驗證」,按鈕,下方顯示預設的是「個別使用者帳戶」。

ASP.NET Identity 支援數種不同的身份驗證機制,按一下「變更驗證」按鈕,開啟設定對話方塊,可以切換不同的驗證機制,目前維持預設「個別使用者帳戶」。

按一下「OK」按鈕回到「新增ASP.NET專案」畫面,建立一個新專案 Auth 。現在執行專案,首頁右上角提供了「登入」與「註冊」功能連結。

按一下「註冊」連結,進入「註冊」畫面建立新的使用者。

填入使用者資訊,按一下畫面下方的「註冊」按鈕,即可建立一個新的使用者,回到原來的首頁,右上角出現的是歡迎訊息「你好SEAN」與「登出」連結,表示目前以新建立的身份操作網頁。

現在開啟專案的Controllers資料夾,其中的控制器檔案AccountController.cs支援相關作業。當你註冊一個新的會員身份時,Account控制器中的Register動作被調用,內容如下:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
    if (ModelState.IsValid)
    {
        var user = new ApplicationUser() { UserName = model.UserName };
        var result = await UserManager.CreateAsync(user, model.Password);
        if (result.Succeeded)
        {
            await SignInAsync(user, isPersistent: false);
            return RedirectToAction("Index", "Home");
        }
        else
        {
            AddErrors(result);
        }
    }
    // 如果執行到這裡,發生某項失敗,則重新顯示表單
    return View(model);
}

 

其中呼叫 Identity API ,以傳送進來的 model 參數為依據建立一個新的使用者,一旦建立成功,接下來便是引用 SignInAsync() 這個方法進行登入,內容如下:

 

private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
            AuthenticationManager.SignOut(
DefaultAuthenticationTypes.ExternalCookie);
            var identity = await UserManager.CreateIdentityAsync(user,
 DefaultAuthenticationTypes.ApplicationCookie);
            AuthenticationManager.SignIn(
new AuthenticationProperties() { IsPersistent = isPersistent },
identity);
}

 

這個方法首先調用 AuthenticationManager 的SignOut 方法將已登入的使用者登出,然後建立根據傳入的識別身份資訊之後,重新登入。因此上述帳號建立程序完成之後,便即刻登入應用程式。 一旦完成登入作業,回到Register方法,return 敘述回應 HomeController 控制器中的Index動作,執行對應的檢視檔案Home/Index.cshtml並將結果回傳,由於 Index.cshtml 套用了_Layout.cshtml 樣板,而其中的登入功能由以下的 Partial() 方法嵌入主網頁當中:

參數 _LoginPartial 表示將 _LoginPartial.cshtml 嵌入這個位置,而這個檔案的內容如下:

一開始的 if 判斷式中,Request.IsAuthenticated會根據目前使用者身份回傳驗證結果,如果已完全登入,這個結果將會是true ,並且呈現使用者歡迎訊息,否則的話,執行 else 區塊,其中顯示「註冊」、「登入」的功能連結按鈕,這表示使用者未完成任何身份驗證操作,而這也是專案第一次執行時呈現這兩個功能連結按鈕的原因。上述程式碼畫面中if判斷式的true區塊裏,緊接著歡迎訊息下方便是預設的「登出」功能,列舉如下:

<a href="javascript:document.getElementById('logoutForm').submit()">登出</a>

 

當這個超連結按下之後,會送出 logoutForm 表單,此表單配置於畫面上方,內容如下:

 

using (Html.BeginForm("LogOff", "Account",
FormMethod.Post,
new { id = "logoutForm", @class = "navbar-right" }))
{
   
}

 

表單內容傳送出去之後被導向AccountController.cs 控制器中的 LogOff() :

 

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{
    AuthenticationManager.SignOut();
    return RedirectToAction("Index", "Home");
}

 

網底標示的程式碼,透過AuthenticationManager引用SignOut()移除使用者的身份驗證,完成登 出,再次回到主頁,並且呈現「註冊」、「登入」的功能連結按鈕。在_LoginPartial.cshtml檢視裏面,這個按鈕的連結如下:

 

@Html.ActionLink("登入", "Login", "Account",
routeValues: null,
htmlAttributes: new { id = "loginLink" })

 

接下來要求被送至 AccountController 控制器中GET版本的 Login 動作,有兩個相關的動作如下:

 

// GET: /Account/Login
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
    ViewBag.ReturnUrl = returnUrl;
    return View();
}

 

當連結要求傳送出去之後,首先會執行第一個版本的Login動作,執行登入檢視頁 Login.cshtml的內容並且將其送出,其中配置了登入作業所需的輸入控制欄位:

 

 

第一行宣告表示其中的登入資訊將對應至強型別Auth.Models.LoginViewModel,接下來的 Html.BeginForm() 方法參數,指定表單的資料將回傳至AccountController控制器中的動作Login如下:

 

// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        var user = await UserManager.FindAsync(model.UserName, model.Password);
        if (user != null)
        {
            await SignInAsync(user, model.RememberMe);
            return RedirectToLocal(returnUrl);
        }
        else
        {
            ModelState.AddModelError("", "Invalid username or password.");
        }
    }
 
    // 如果執行到這裡,發生某項失敗,則重新顯示表單
    return View(model);
}

 

登入資訊被封裝為 LoginViewModel 型別當作參數傳入,其中引用UserManager.FindAsync() 並將使用者資訊 model 當作參數傳入,以驗證是否為合法使用者,是的話引用 SignInAsync() 完成登入作業,否則返回原來的登入頁。從「註冊」、「登出」到「登入」,我們完成了APS.NET MVC 內建驗證機制的討論,當然,這些基礎的功能並不能滿足實際的開發需求,除了驗證之外,接下來必須進一步加入授權系統,以支援完整的會員管理機制。接下來,我們將開始逐一在康廷數位購物網站裏面,逐一整合各種管理功能,除此之外,ASP.NET MVC 專案內建的 ASP.NET Identity機制還沒有討論完,未觸及的部份,在後續實作時,將進一步作說明。