ASP.NET Core - 登入和登出



本章將討論登入和登出功能。與登入相比,登出的實現比較簡單。讓我們從佈局檢視開始,因為我們想要構建一個包含一些連結的UI。這將允許已登入使用者登出並顯示使用者名稱。

<!DOCTYPE html>  
<html> 
   <head> 
      <meta name = "viewport" content = "width = device-width" /> 
       <title>@ViewBag.Title</title> 
   </head> 

   <body> 
      <div> 
         @DateTime.Now 
      </div> 
      
      <div> 
         @RenderBody() 
      </div> 

   </body> 
</html>
  • 對於匿名使用者,我們將顯示一個登入連結。

  • 構建此UI所需的所有資訊都可從Razor檢視上下文獲取。

  • 首先,讓我們在佈局檢視中新增名稱空間`System.Security.Claims`。

@using System.Security.Claims 
<!DOCTYPE html>  
<html> 
   
   <head> 
      <meta name = "viewport" content = "width = device-width" /> 
      <title>@ViewBag.Title</title> 
   </head> 

   <body>
      <div> 
         @if (User.IsSignedIn()) { 
            <div>@User.GetUserName()</div> 
            <form method = "post" asp-controller = "Account" aspcontroller = "Logout"> 
               <input type = "submit" value = "Logout"/> 
            </form> 
         } else {  
            <a asp-controller = "Account" asp-action = "Login">Login</a> 
            <a asp-controller = "Account" asp-action = "Register">Register</a> 
         } 
      </div> 
    
      <div> 
         @DateTime.Now 
      </div> 
    
      <div> 
         @RenderBody() 
      </div> 

   </body> 
</html>
  • 在每個Razor檢視中都可使用一個`User`屬性,我們想要構建一個顯示已登入使用者名稱 的UI。這裡還提供了一個擴充套件方法`IsSignedIn`。

  • 我們可以呼叫此方法,如果它返回true,則可以在此處放置一些標記來顯示使用者名稱,顯示登出按鈕。

  • 現在,如果使用者已登入,我們可以使用輔助方法`GetUserName`顯示使用者的使用者名稱。

  • 我們必須在一個表單內構建登出按鈕,該表單將釋出到Web伺服器。必須這樣做,因為如果允許簡單的GET請求讓使用者退出,則會產生某些不良情況。

  • 我們將強制將其設定為POST請求,當用戶提交此表單時,我們只需要點選登出操作(我們將透過`AccountController`實現),然後登出使用者。

  • 如果使用者未登入並且我們有匿名使用者,則需要顯示一個連結,該連結將轉到`AccountController`,特別是`Login`操作,並且可以顯示文字“登入”。

  • 我們還需要為新使用者新增一個註冊連結,直接跳轉到註冊頁面。

現在讓我們轉到`AccountController`並首先實現登出操作,如下面的程式所示。

[HttpPost] 
public async Task<IActionResult> Logout() { 
   await _signManager.SignOutAsync(); 
   return RedirectToAction("Index", "Home"); 
} 
  • 此操作僅響應HttpPost。這是一個非同步操作。我們必須在Identity框架上呼叫另一個非同步方法。

  • 我們可以返回`IActionResult`的任務,操作名為`Logout`。

  • 登出所需做的就是等待`SignInManager's SignOutAsync`方法。

  • 使用者上下文現在已更改;我們現在有了一個匿名使用者。檢視將重定向到主頁,我們將返回到員工列表。

現在讓我們繼續構建登入功能。這裡,我們需要一對操作,一個響應HttpGet請求並顯示我們可以用來登入的表單,另一個響應HttpPost請求。

首先,我們需要一個新的ViewModel來提取登入資料,因為登入與註冊非常不同。因此,讓我們新增一個新類並將其命名為`LoginViewModel`。

public class LoginViewModel { 
   public string Username { get; set; }  
   
   [DataType(DataType.Password)] 
   public string Password { get; set; }  
   
   [Display(Name ="Remember Me")] 
   public bool RememberMe { get; set; } 
   public string ReturnUrl { get; set; } 

}
  • 當用戶登入時,他們必須提供一些資訊,例如使用者名稱、密碼。

  • 第三條資訊必須是登入UI。這些帶有一個小複選框,上面寫著——“您是否要記住我”。這是我們是否想要會話cookie或更永久的cookie的選擇。

  • 為了允許此功能,我們添加了一個布林屬性`RememberMe`,並使用了`Display`特性。現在,當我們構建標籤時,文字“記住我”將帶空格顯示。

  • 我們實際上希望作為此ViewModel一部分的最後一條資訊是擁有一個將儲存`ReturnUrl`的屬性。

現在讓我們新增將響應Get請求的`Login`操作,如下面的程式所示。

[HttpGet] 
public IActionResult Login(string returnUrl = "") { 
   var model = new LoginViewModel { ReturnUrl = returnUrl }; 
   return View(model); 
}
  • 我們將`returnUrl`作為查詢字串中的引數。

  • `returnUrl`可能並不總是存在。讓我們使用空字串作為預設值。

我們現在將透過在`Views → Account`資料夾中新增新的MVC檢視頁面來新增一個新檢視。

Log in Log Out Add New Item

在中間窗格中,選擇MVC檢視頁面並將其命名為`Login.cshtml`,然後單擊“新增”按鈕。讓我們在`Login.cshtml`檔案中新增以下程式碼。

@model LoginViewModel 
@{ 
   ViewBag.Title = "Login"; 
}  
<h2>Login</h2>  

<form method = "post" asp-controller = "Account" asp-action = "Login" 
   asp-route-returnurl = "@Model.ReturnUrl"> 
      <div asp-validation-summary = "ValidationSummary.ModelOnly"></div> 
      
      <div> 
         <label asp-for = "Username"></label> 
         <input asp-for = "Username" /> 
         <span asp-validation-for = "Username"></span> 
      </div> 
      
      <div> 
         <label asp-for = "Password"></label> 
         <input asp-for = "Password" />
         <span asp-validation-for = "Password"></span> 
      </div> 
    
      <div> 
         <label asp-for = "RememberMe"></label> 
         <input asp-for = "RememberMe" /> 
         <span asp-validation-for = "RememberMe"></span> 
      </div> 
   <input type = "submit" value = "Login" /> 
</form>        
  • 在此登入檢視中,我們將頁面的標題設定為“登入”,然後我們有一個表單,它將釋出到`AccountLogin`操作。

  • 我們需要使用標籤助手`asp-route-returnurl`來確保`ReturnUrl`存在於表單釋出到的URL中。

  • 我們需要將`ReturnUrl`傳送回伺服器,以便如果使用者成功登入,我們可以將其傳送到他們試圖到達的地方。

  • 在`asp-route-`之後新增的任何內容,例如id或returnurl,無論您在那裡有什麼,都將進入請求中的某個位置,要麼進入URL路徑,要麼作為查詢字串引數。

  • 我們有`ValidationSummary`和使用者名稱、密碼和`RememberMe`的輸入,然後我們有一個提交按鈕。

`AccountController`,並實現Post操作。此操作響應HttpPost。這將是一個非同步方法,因為我們需要呼叫Identity框架並返回`IActionResult`的任務。

[HttpPost] 
public async Task<IActionResult> Login(LoginViewModel model) { 
   if (ModelState.IsValid) { 
      var result = await _signManager.PasswordSignInAsync(model.Username,
         model.Password, model.RememberMe,false); 
      
      if (result.Succeeded) { 
         if (!string.IsNullOrEmpty(model.ReturnUrl) && Url.IsLocalUrl(model.ReturnUrl)) {
            return Redirect(model.ReturnUrl);
         } else { 
            return RedirectToAction("Index", "Home"); 
         } 
      } 
   } 
   ModelState.AddModelError("","Invalid login attempt"); 
   return View(model); 
}
  • 我們稱之為`Login`,現在我們期望接收一個`LoginViewModel`。

  • 我們需要檢查`ModelState`是否有效。如果有效,則透過呼叫`SignInManager`上的API來登入使用者。

  • `PasswordSignInAsync`方法將返回一個結果,如果結果成功,我們就知道使用者已成功登入。

  • 我們還有一個`returnUrl`。如果它是一個有效的本地Url,我們將被重定向到`returnUrl`。

  • 如果使用者剛剛登入並且沒有任何特定的地方要去,我們將把使用者重定向到`HomeController`的`Index`操作。

  • 我們可能遇到使用者提供無效密碼或無效使用者名稱的情況。我們還需要新增一個模型錯誤,提示是否存在無效的登入嘗試。這有助於使用者知道是否出現錯誤。

現在讓我們儲存所有內容並執行應用程式。

Login Register

我們現在有“登入”和“註冊”連結。讓我們點選“登入”連結。

Login Register Link

讓我們使用我們在上一章中建立的使用者登入,指定`使用者名稱`和`密碼`,並選中`記住我`複選框。

單擊“登入”按鈕時,瀏覽器會詢問您是否要儲存localhost的密碼。讓我們單擊“是”按鈕。

Logout

現在,讓我們透過單擊“登出”按鈕登出。

Logout Button

作為匿名使用者,讓我們嘗試編輯員工詳細資訊。

Anonymous User

您現在可以看到我們已被重定向到`Login`檢視。

讓我們使用您的使用者名稱和密碼登入,並選中“記住我”複選框。

Check Remember Me

現在,單擊“登入”按鈕。

Login Button

您現在可以看到我們被定向到我們想要編輯的URL。這是因為我們適當地處理了`returnUrl`。

廣告
© . All rights reserved.