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 REQUEST 允许用户退出,则必须这样做,因为它会产生某些不利条件。

  • 我们将强制这是一个 post,当用户提交此表单时,我们需要做的就是点击注销操作,我们将通过 AccountController 实现该操作,然后注销用户。

  • 如果用户未登录并且我们有一个匿名用户,那么我们需要显示一个链接,该链接将转到 AccountController,特别是登录操作,它可以显示文本登录。

  • 我们还需要添加一个链接,供新用户注册,直接进入注册页面。

现在让我们转到 AccountController 并首先执行注销操作,如下面的程序所示。

[HttpPost] 
public async Task<IActionResult> Logout() { 
   await _signManager.SignOutAsync(); 
   return RedirectToAction("Index", "Home"); 
} 
  • 此操作仅响应 HttpPost。 这是一个异步操作。 我们将不得不在 Identity 框架上调用另一个异步方法。

  • 我们可以返回一个 IActionResult 的任务,动作名为 Logout。

  • 要注销,我们需要做的就是等待 SignInManager 的 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; } 

}
  • 当用户登录时,他们必须提供用户名、密码等信息。

  • 第三条信息必须是登录界面。 这些带有一个小复选框,上面写着——"Do you want to remember me"。 这是我们想要会话 cookie 还是想要更永久的 cookie 之间的选择。

  • 为实现此功能,我们添加了布尔属性 RememberMe 并使用了 Display 注释。 现在,当我们构建标签时,文本 Remember Me 会显示一个空格。

  • 作为此 ViewModel 的一部分,我们真正想要的最后一个信息是拥有一个用于存储 ReturnUrl 的属性。

现在让我们添加将响应 Get 请求的登录操作,如以下程序所示。

[HttpGet] 
public IActionResult Login(string returnUrl = "") { 
   var model = new LoginViewModel { ReturnUrl = returnUrl }; 
   return View(model); 
}
  • 我们会将 returnUrl 作为查询字符串中的参数。

  • returnUrl 可能并不总是存在。 让我们有一个空字符串作为默认值。

我们现在将通过在 Views → Account 文件夹中添加一个新的 MVC 视图页面来获得一个新视图。

登录 注销 添加新项目

在中间窗格中,选择 MVC 视图页面并将其命名为 Login.cshtml,然后单击"Add"添加按钮。 让我们在 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。 这将是一个异步方法,因为我们需要调用身份框架并返回一个任务或 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); 
}
  • 我们称之为登录,现在我们希望收到一个登录视图模型。

  • 我们需要检查 ModelState 是否有效。 如果有效,则通过调用 SignInManager 上的 API 使用户登录。

  • PasswordSignInAsync 方法将返回一个结果,如果结果成功,我们就知道用户已成功登录。

  • 我们还有一个返回 URL。 如果它是有效的本地 Url,我们将被重定向到返回 URL。

  • 如果用户刚刚登录并且没有任何特定的去处,我们会将用户重定向到 HomeController 的 Index 操作。

  • 我们可能会遇到用户提供无效密码或无效用户名的情况。 我们还需要添加一个模型错误,提示是否存在无效登录尝试。 这有助于用户知道是否出了问题。

现在让我们保存所有内容并运行应用程序。

登入注册

我们现在有登录和注册链接。 让我们点击登录链接。

登录注册链接

让我们通过指定UsernamePassword 并选中Remember Me 复选框来使用我们在上一章中创建的用户登录。

当您单击"Login"登录按钮时,浏览器会询问您是否要保存本地主机的密码。 让我们单击"Yes"按钮。

Logout

现在,让我们通过单击注销按钮来注销。

注销按钮

作为匿名用户,让我们去尝试编辑员工详细信息。

匿名用户

现在您可以看到我们已被重定向到 Login 登录视图

让我们使用您的用户名和密码登录,然后选中"Remember Me"复选框。

选中 Remember Me

现在,点击 Login 登录按钮。

Login 按钮

您现在可以看到我们被定向到要编辑的 URL。 这是因为我们对返回 URL 进行了适当的处理。