ASP.NET Core – 登录和注销
ASP.NET Core – 登录和注销
在本章中,我们将讨论登录和注销功能。与登录相比,注销实现起来相当简单。让我们继续 Layout 视图,因为我们想要构建一个包含一些链接的 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>
-
对于匿名用户,我们将显示登录链接。
-
您可以从 Razor 视图上下文中获得构建此 UI 所需的所有信息。
-
首先,让我们在您的布局视图中添加命名空间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 允许用户退出,它会产生某些令人讨厌的情况。
-
我们将强制这是一个帖子,当用户提交这个表单时,我们需要做的就是点击注销操作,我们将通过 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; } }
-
当用户登录时,他们必须提供一些信息,如用户名、密码。
-
第三条信息必须是登录用户界面。这些带有一个小复选框,上面写着——“你想记住我吗”。这是我们想要一个会话 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 View Page 来获得一个新视图。
在中间窗格中,选择 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和用户名、密码和记住我的输入,然后我们有一个提交按钮。
` 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); }
-
我们称之为登录,现在我们期望收到一个 LoginViewModel。
-
我们需要检查 ModelState 是否有效。如果有效,则通过调用 SignInManager 上的 API 来登录用户。
-
该PasswordSignInAsync方法会返回一个结果,如果结果成功了,我们知道用户成功登录。
-
我们还有一个返回 URL。如果它是一个有效的本地 URL,我们将被重定向到返回 URL。
-
如果用户刚刚登录并且没有任何特定的去处,我们会将用户重定向到 HomeController 的 Index 操作。
-
我们可能会遇到用户提供无效密码或无效用户名的情况。我们还需要添加一个模型错误,提示是否存在无效登录尝试。这有助于用户知道是否出现问题。
现在让我们保存所有内容并运行应用程序。
我们现在有登录和注册链接。让我们点击登录链接。
让我们通过指定用户名和密码使用我们在上一章中创建的用户登录,然后选中“记住我”复选框。
当您单击“登录”按钮时,浏览器会询问您是否要保存本地主机的密码。让我们点击是按钮。
现在,让我们通过单击注销按钮注销。
作为匿名用户,让我们尝试编辑员工详细信息。
您现在可以看到我们已被重定向到登录视图。
让我们使用您的用户名和密码登录并选中“记住我”复选框。
现在,单击登录按钮。
您现在可以看到我们被定向到要编辑的 URL。这是因为我们适当地处理了返回 URL。