如何在 ASP.NET Core Identity 中实现用户身份验证

目录

[ASP.NET Core Identity 中的身份验证工作原理](#ASP.NET Core Identity 中的身份验证工作原理)

[在身份验证中更改默认登录 URL](#在身份验证中更改默认登录 URL)

[ASP.NET Core 身份验证](#ASP.NET Core 身份验证)

[ASP.NET Core Identity 登录页面](#ASP.NET Core Identity 登录页面)

代码说明

显示已登录用户的姓名

[ASP.NET Core 身份注销](#ASP.NET Core 身份注销)

[ASP.NET Core 身份 Cookie](#ASP.NET Core 身份 Cookie)

[身份 Cookie 超时](#身份 Cookie 超时)

[ASP.NET Core Identity 记住我](#ASP.NET Core Identity 记住我)


如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

示例代码:https://download.csdn.net/download/hefeng_aspnet/92599900

ASP.NET Core 中的身份验证是什么?身份验证是指在用户成功登录应用程序时识别其身份的过程。ASP.NET Core Identity 会显示一个登录表单,用户需要在其中输入用户名和密码进行身份验证。登录成功后,Identity 会验证用户身份,并授予其访问 ASP.NET Core 应用程序安全资源的权限。

ASP.NET Core Identity 中的身份验证工作原理

让我们创建ASP.NET Core 身份验证 功能,该功能仅允许经过身份验证的用户访问控制器。首先,创建一个名为HomeController.cs的新控制器,并添加一个名为++Secured 的++ 操作方法,该方法向视图返回字符串消息" ++Hello "。++

复制代码
using Microsoft.AspNetCore.Mvc;

namespace Identity.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Secured()
        {
            return View((object)"Hello");
        }
    }
}

接下来,在Views ➤ Home文件夹中添加++Secured.cshtml++ Razor 视图,并添加以下代码:

复制代码
@model string

@{
    ViewData["Title"] = "Authentication";
}

<h1 class="bg-info text-white">Secured</h1>
@Model

该视图除了显示控制器返回的字符串"Hello"之外,没有其他特殊功能。现在运行项目,您将在浏览器中看到++"Hello"消息,请参见下图:++

这里不需要身份验证,所以我们可以不受任何限制地调用安全操作方法。运行应用程序时,浏览器向主控制器的安全操作方法发送了一个++未经身份验证的请求++ (匿名请求)。这个未经身份验证的请求能够访问应用程序资源,也就是主控制器,因此我们在浏览器上看到了"Hello"消息。

现在我们将通过应用身份验证来 ++限制++ 安全操作,以便用户必须先进行身份验证,然后身份验证系统才会授权他们调用操作方法。

请注意,身份授权与身份验证不同,它是在用户通过身份验证后才生效的。身份授权是指,只有在用户通过身份验证后,系统才会授权用户访问应用程序上的资源。

应用身份验证非常简单,只需在 Secured 操作方法上应用Microsoft.AspNetCore.Authorization命名空间的[Authorize]特性即可。这将限制只有经过身份验证的用户才能访问该方法。

复制代码
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Identity.Controllers
{
    public class HomeController : Controller
    {
        [Authorize]
        public IActionResult Secured()
        {
            return View((object)"Hello");
        }
    }
}

现在再次运行该应用程序,这次我们会看到一条消息,提示"找不到本地主机页面。HTTP 错误 404"。如下图所示:

这里发生了两件事:

请注意,URL 包含名为++ReturnUrl 的++ 查询字符串变量,其中包含++%2F++ 。%2F是经过编码的 URL,代表++/++ 。因此,身份验证后,用户将被重定向到应用程序的主页 URL,即http://localhost:7263

返回的 URL 将包含用户在身份验证之前尝试访问的安全页面 URL。身份验证成功后,身份系统会将用户重定向回该原始页面。

在身份验证中更改默认登录 URL

ASP.NET Core Identity 的默认登录 URL 为/Account/Login ,用户将被++重定向++ 到此处进行身份验证。此处会显示一个登录表单,供用户在 Identity 中完成登录流程。如果要更改此登录 URL,请转到++Program 类++并添加以下代码:

builder.Services.ConfigureApplicationCookie(opts => opts.LoginPath = "/Authenticate/Login");

这里我们将新的登录 URL 指定为/Authenticate/Login,即++https://localhost:7263/Authenticate/Login++ 。您的端口可能有所不同。请注意,此 URL 不能基于应用程序中的路由自动生成,因此,如果更改路由,则必须手动更改此处的++身份登录 URL++。

ASP.NET Core 身份验证

为了实现**身份验证,**我们需要创建两个页面------登录页面和注销页面。在登录页面,用户需要输入用户名和密码进行身份验证;在注销页面,用户可以点击注销按钮,即可从身份验证系统中注销。

ASP.NET Core Identity 登录页面

在Models文件夹内创建一个名为Login.cs 的类。该类包含三个属性:++Email、Password 和 ReturnUrl++,用于存储用户的登录信息。

由于用户登录时必须输入电子邮件和密码,因此这两个属性被设置为必填字段。ReturnUrl 属性将包含返回URL。

++Login.cs++类的代码如下:

复制代码
using System.ComponentModel.DataAnnotations;

namespace Identity.Models
{
    public class Login
    {
        [Required]
        public string Email { get; set; }

        [Required]
        public string Password { get; set; }

        public string ReturnUrl { get; set; }
    }
}

Identity 的默认登录 URL 为++https://localhost:7263/Account/Login++ 。因此,我们需要创建++Account 控制器++ ,它将作为Identity 的登录控制器 。我们还将添加++Login 操作++方法,该方法将在用户执行登录操作时触发。

因此,请在++Controllers文件夹中创建++ AccountController.cs类,并添加以下代码:

using Identity.Models;

using Microsoft.AspNetCore.Authorization;

using Microsoft.AspNetCore.Identity;

using Microsoft.AspNetCore.Mvc;

namespace Identity.Controllers

{

Authorize

public class AccountController : Controller

{

private UserManager<AppUser> userManager;

private SignInManager<AppUser> signInManager;

public AccountController(UserManager<AppUser> userMgr, SignInManager<AppUser> signinMgr)

{

userManager = userMgr;

signInManager = signinMgr;

}

AllowAnonymous

public IActionResult Login(string returnUrl)

{

Login login = new Login();

login.ReturnUrl = returnUrl;

return View(login);

}

HttpPost

AllowAnonymous

ValidateAntiForgeryToken

public async Task<IActionResult> Login(Login login)

{

if (ModelState.IsValid)

{

AppUser appUser = await userManager.FindByEmailAsync(login.Email);

if (appUser != null)

{

await signInManager.SignOutAsync();

Microsoft.AspNetCore.Identity.SignInResult result = await signInManager.PasswordSignInAsync(appUser, login.Password, false, false);

if (result.Succeeded)

return Redirect(login.ReturnUrl ?? "/");

}

ModelState.AddModelError(nameof(login.Email), "Login Failed: Invalid Email or password");

}

return View(login);

}

}

}

代码说明

控制器类应用了[Authorize]特性,以防止++未经身份验证的++ 请求调用它。但是,我们为登录操作方法添加了[AllowAnonymous]特性,允许++未经身份验证的++请求调用这些操作方法。

请注意,必须允许未经身份验证的用户查看登录页面,否则他永远无法登录身份系统。

我们在控制器构造函数中添加了UserManager<AppUser>和SignInManager<AppUser>的依赖项,以便这些对象将由ASP.NET Core 的依赖注入功能提供。

相关代码如下:

private UserManager<AppUser> userManager;

private SignInManager<AppUser> signInManager;

public AccountController(UserManager<AppUser> userMgr, SignInManager<AppUser> signinMgr)

{

userManager = userMgr;

signInManager = signinMgr;

}

UserManager用于管理身份系统中的用户,而 SignInManager用于执行身份验证过程。

接下来,我们添加了登录操作方法的 HTTP GET 版本。我们为其应用了[AllowAnonymous]特性,使其无需身份验证。这一点显而易见,否则用户将无法登录。

此操作的参数中包含一个returnUrl变量,其值由ReturnUrl查询字符串变量提供。在后台,模型绑定会自动将返回 URL 值绑定到此变量。

操作方法代码为:

AllowAnonymous

public IActionResult Login(string returnUrl)

{

Login login = new Login();

login.ReturnUrl = returnUrl;

return View(login);

}

该操作会将++Login 类对象++ 作为模型返回给视图。请注意,我们将ReturnUrl属性的值设置为传递给该操作参数的值。

接下来,我们添加了登录操作方法的 POST 版本,用于执行用户的实际身份验证。该操作方法的代码如下:

HttpPost

AllowAnonymous

ValidateAntiForgeryToken

public async Task<IActionResult> Login(Login login)

{

if (ModelState.IsValid)

{

AppUser appUser = await userManager.FindByEmailAsync(login.Email);

if (appUser != null)

{

await signInManager.SignOutAsync();

Microsoft.AspNetCore.Identity.SignInResult result = await signInManager.PasswordSignInAsync(appUser, login.Password, false, false);

if (result.Succeeded)

return Redirect(login.ReturnUrl ?? "/");

}

ModelState.AddModelError(nameof(login.Email), "Login Failed: Invalid Email or password");

}

return View(login);

}

此操作方法有一个类型为Login.cs的参数,它通过该参数接收用户在Login.cshtml提供的登录表单中填写的登录值(即电子邮件和密码) 。该方法提供两个属性:

  1. AllowAnonymous\]属性允许未经身份验证的请求调用它。

首先,我们从UserManager类的FindByEmailAsync()方法中获取用户详细信息。此方法接收用户在登录表单中提供的电子邮件地址。请参见以下代码:

AppUser appUser = await userManager.FindByEmailAsync(login.Email);

接下来,我们检查AppUser对象中接收到的用户详细信息是否不为空。如果为空,我们首先会注销所有已登录的用户:

await signInManager.SignOutAsync();

然后我们使用SignInManager类的PasswordSignInAsync方法将用户登录到应用程序。

Microsoft.AspNetCore.Identity.SignInResult result = await signInManager.PasswordSignInAsync(appUser, login.Password, false, false);

我们为最后第三个和第四个参数都提供了错误的值,因为我们既不希望持久登录使用持久 cookie(即使关闭浏览器后仍然存在),也不希望在登录失败时锁定用户帐户。

此方法返回SignInResult对象,其中包含登录过程的结果。如果登录成功,则其Succeeded属性包含true值,否则包含false 值。

最后,我们检查 ` Succeeded` 属性的值是否为真。如果是真,则将用户返回到返回 URL 的值。实现此功能的代码如下:

if (result.Succeeded)

return Redirect(login.ReturnUrl ?? "/");

我们还需要登录视图,其中包含登录表单。此视图将构成身份登录页面,用户将在此执行帐户登录流程。因此,请在Views/Account文件夹中创建Login.cshtml Razor 视图文件,并添加如下所示的代码:

@model Login

@{

ViewData["Title"] = "Login";

}

<h1 class="bg-info text-white">Login</h1>

<div class="text-danger" asp-validation-summary="All"></div>

<form asp-action="Login" method="post">

<input type="hidden" asp-for="ReturnUrl" />

<div class="form-group">

<label asp-for="Email"></label>

<input asp-for="Email" class="form-control" />

</div>

<div class="form-group">

<label asp-for="Password"></label>

<input asp-for="Password" class="form-control" />

</div>

<button class="btn btn-primary" type="submit">Log In</button>

</form>

是时候测试身份验证功能了。我们已经注册了一个用户,其详细信息如下:

  1. 姓名 -- tom

  2. 邮箱 -- tom@yahoo.com

  3. 密码 -- Coder77@

现在我们将使用该用户的凭据登录。

如果您没有任何用户,请从 URL 创建一个新用户 -- https://localhost:7263/Admin/Create。

运行项目并访问"安全"链接(网址:https://localhost:7236/Home/Secured)。您将被重定向到登录页面。在此输入错误的登录凭据:

  1. 邮箱:tom@yahoo.com

  2. 密码:wrongpass

点击"登录"按钮后,我们会看到"登录失败:邮箱或密码无效"的提示信息。这是因为我们输入了错误的密码,请参见下图:

现在输入++正确的密码++ ,然后点击"登录"按钮。这次验证成功,您将被重定向到安全页面,页面上会显示"Hello"消息。请查看下图。

显示已登录用户的姓名

我们可以通过UserManager类的GetUserAsync()方法获取 Identity 中的当前用户。然后,我们可以在视图中显示当前用户名。请查看以下代码,了解如何获取已登录用户的姓名。

AppUser user = await userManager.GetUserAsync(HttpContext.User);

编辑Home Controller 的代码,获取用户并将其姓名发送到视图。

using Identity.Models;

using Microsoft.AspNetCore.Authorization;

using Microsoft.AspNetCore.Identity;

using Microsoft.AspNetCore.Mvc;

namespace Identity.Controllers

{

public class HomeController : Controller

{

private UserManager<AppUser> userManager;

public HomeController(UserManager<AppUser> userMgr)

{

userManager = userMgr;

}

Authorize

public async Task<IActionResult> Secured()

{

AppUser user = await userManager.GetUserAsync(HttpContext.User);

string message = "Hello " + user.UserName;

return View((object)message);

}

}

}

现在,用户登录后,其姓名将显示在浏览器上。

ASP.NET Core 身份注销

注销功能会将已登录用户从身份管理界面注销。因此,请在AccountController.cs文件中添加以下代码来实现注销操作方法:

public async Task<IActionResult> Logout()

{

await signInManager.SignOutAsync();

return RedirectToAction("Index", "Home");

}

注销操作相当简单,它只是使用signInManager.SignOutAsync()将任何已登录用户从应用程序中注销。

应该使用锚点标签将注销操作方法链接到Secured.cshtml Razor 视图文件中。因此,请按如下所示更新此视图:

@model string

@{

ViewData["Title"] = "Authentication";

}

<h1 class="bg-info text-white">Index</h1>

@Model

@if (User?.Identity?.IsAuthenticated ?? false)

{

<a asp-controller="Account" asp-action="Logout" class="btn btn-danger">Logout</a>

}

这里我们使用了Microsoft.AspNetCore.Mvc.Razor命名空间中的RazorPageBase类。该类的User.Identity.IsAuthenticated属性在用户登录时返回 true,否则返回null。我们利用这一点,仅在用户登录应用程序时才显示"注销"链接。

运行应用并使用用户帐户登录。登录后,您将被重定向到主页,在那里可以看到"注销"按钮。单击该按钮即可从 ASP.NET Core Identity 注销。请参见下图:

ASP.NET Core Identity 使用++Cookie++ 来确定用户当前是否++已通过身份验证++ 。此 Cookie 在用户通过身份验证后创建并存储在浏览器中。每次发出++HTTP 请求++时(例如,当我们在浏览器中打开应用程序的任何 URL 时),都会将相同的 Cookie 发送到服务器。这使得 Identity 能够确定请求来自哪个用户。

此 Cookie 名称为++.AspNetCore.Identity.Application 。我们可以在 Chrome 浏览器开发者工具的++ "应用程序"选项卡中查看此 Cookie 。请参见下图:


注意 -- 要从 Identity 中注销任何用户,只需选择此 cookie 并单击"X"符号即可删除此 cookie。

我们可以使用++IServiceCollection++ 接口的ConfigureApplicationCookie方法设置ASP.NET Core Identity Cookie 的++过期时间++。

我们在 Program 类中使用以下代码,以滑动过期方式将过期时间设置为 20 分钟。

builder.Services.ConfigureApplicationCookie(options =>

{

options.Cookie.Name = ".AspNetCore.Identity.Application";

options.ExpireTimeSpan = TimeSpan.FromMinutes(20);

options.SlidingExpiration = true;

});

ASP.NET Core Identity 记住我

我们将创建**"记住我"**功能,确保 Identity 能够长时间记住我们。我们只需首次登录,Identity 就会在浏览器中为我们创建一个持久性 cookie。

为了实现这个功能,我们需要在登录页面添加一个"记住我"复选框。

@model Login

@{

ViewData["Title"] = "Login";

}

<h1 class="bg-info text-white">Login</h1>

<div class="text-danger" asp-validation-summary="All"></div>

<form asp-action="Login" method="post">

<input type="hidden" asp-for="ReturnUrl" />

<div class="form-group">

<label asp-for="Email"></label>

<input asp-for="Email" class="form-control" />

</div>

<div class="form-group">

<label asp-for="Password"></label>

<input asp-for="Password" class="form-control" />

</div>

<div class="form-group">

Remember me? <input type="checkbox" asp-for="Remember" />

</div>

<button class="btn btn-primary" type="submit">Log In</button>

</form>

现在在 Login.cs 类中添加一个名为 Remember 的布尔类型属性,如下所示。

public class Login

{

Required

public string Email { get; set; }

Required

public string Password { get; set; }

public string ReturnUrl { get; set; }

public bool Remember { get; set; }

}

该属性将通过模型绑定技术自动绑定到"记住我"复选框的值。

现在我们可以将此属性值分配给"PasswordSignInAsync"方法的第三个参数,如下所示。

HttpPost

AllowAnonymous

ValidateAntiForgeryToken

public async Task<IActionResult> Login(Login login)

{

if (ModelState.IsValid)

{

AppUser appUser = await userManager.FindByEmailAsync(login.Email);

if (appUser != null)

{

await signInManager.SignOutAsync();

Microsoft.AspNetCore.Identity.SignInResult result = await signInManager.PasswordSignInAsync(appUser, login.Password, login.Remember, false);

if (result.Succeeded)

return Redirect(login.ReturnUrl ?? "/");

}

ModelState.AddModelError(nameof(login.Email), "Login Failed: Invalid Email or password");

}

return View(login);

}

启用此功能后,用户可以选择勾选"记住我"复选框,从此无需再次登录。

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

相关推荐
康小庄2 小时前
SpringBoot 拦截器 (Interceptor) 与切面 (AOP):示例、作用、及适用场景
java·数据库·spring boot·后端·mysql·spring·spring cloud
中科院提名者2 小时前
如何配置go环境并用vscode运行
开发语言·后端·golang
huahailing10242 小时前
Spring Boot 3.x + JDK17 参数校验全场景实战(含List列表_嵌套_分组)
spring boot·后端
毕设源码-朱学姐3 小时前
【开题答辩全过程】以 基于spring boot的摩托车合格证管理系统为例,包含答辩的问题和答案
java·spring boot·后端
毕设源码-赖学姐3 小时前
【开题答辩全过程】以 基于spring boot的国学诗词网站设计与实现--为例,包含答辩的问题和答案
java·spring boot·后端
千寻技术帮3 小时前
10410_基于Springboot的文化旅游宣传网站
spring boot·后端·vue·源码·旅游·安装·在线旅游
源码宝4 小时前
前后端分离架构:不良事件管理系统源码(Vue2+Element UI+Laravel 8)
后端·php·源码·二次开发·程序·不良事件上报·医院不良事件管理系统
Remember_9934 小时前
【LeetCode精选算法】位运算专题
java·开发语言·jvm·后端·算法·leetcode
源代码•宸4 小时前
Leetcode—102. 二叉树的层序遍历【中等】
经验分享·后端·算法·leetcode·职场和发展·golang·slice