ASP.NET Core 上的标识简介Introduction to Identity on ASP.NET Core

本文内容

作者:Rick Anderson

ASP.NET Core 标识:

  • 是支持用户界面(UI)登录功能的 API。
  • 管理用户、密码、配置文件数据、角色、声明、令牌、电子邮件确认等。

用户可以创建一个具有存储在标识中的登录信息的帐户,也可以使用外部登录提供程序。支持的外部登录提供程序包括Facebook、Google、Microsoft 帐户和 Twitter

GitHub 上提供了标识源代码基架标识并查看生成的文件以查看模板与标识的交互。

通常使用 SQL Server 数据库配置标识,以存储用户名、密码和配置文件数据。另外,还可以使用另一个永久性存储,例如 Azure 表存储。

本主题介绍如何使用标识注册、登录和注销用户。有关创建使用标识的应用的更多详细说明,请参阅本文末尾的后续步骤部分。

Microsoft 标识平台是:

  • Azure Active Directory (Azure AD)开发人员平台的演变。
  • 与 ASP.NET Core 标识无关。

ASP.NET Core 标识将用户界面 (UI) 登录功能添加到 ASP.NET Core Web 应用。若要保护 Web API 和 SPA,请使用以下项之一:

IdentityServer4 是适用于 ASP.NET Core 3.0 的 OpenID Connect 和 OAuth 2.0 框架。IdentityServer4 支持以下安全功能:

  • 身份验证即服务 (AaaS)
  • 跨多个应用程序类型的单一登录/注销 (SSO)
  • API 的访问控制
  • Federation Gateway

有关详细信息,请参阅欢迎使用 IdentityServer4

查看或下载示例代码如何下载)

创建具有身份验证的 Web 应用Create a Web app with authentication

使用单个用户帐户创建一个 ASP.NET Core Web 应用程序项目。

  • 选择 "文件" >新建>项目"。
  • 选择“ASP.NET Core Web 应用程序”。将项目命名为WebApp1 ,使其命名空间与项目下载相同。单击“确定”。
  • 选择 ASP.NET Core Web 应用程序,然后选择 "更改身份验证"。
  • 选择单个用户帐户,然后单击 "确定"
  1. dotnet new webapp --auth Individual -o WebApp1

上述命令使用 SQLite 创建 Razor web 应用。若要创建具有 LocalDB 的 web 应用,请运行以下命令:

  1. dotnet new webapp --auth Individual -uld -o WebApp1

生成的项目提供ASP.NET Core 标识作为Razor 类库标识 Razor 类库公开 Identity 区域的终结点。例如:

  • /Identity/Account/Login
  • /Identity/Account/Logout
  • /Identity/Account/Manage

应用迁移Apply migrations

应用迁移以初始化数据库。

在包管理器控制台中运行以下命令(PMC):

PM> Update-Database

使用 SQLite 时,此步骤不需要迁移。对于 LocalDB,请运行以下命令:

  1. dotnet ef database update

测试注册和登录Test Register and Login

运行应用并注册用户。根据屏幕大小,你可能需要选择 "导航" 切换按钮以查看 "寄存器" 和 "登录" 链接。

查看标识数据库View the Identity database

  • 从 "视图" 菜单中选择 " SQL Server 对象资源管理器" (SSOX)。
  • 导航到 (localdb) MSSQLLocalDB (SQL Server 13) 。右键单击 " dbo"。AspNetUsers > 查看数据

SQL Server 对象资源管理器中的 AspNetUsers 表上的上下文菜单

您可以下载许多第三方工具来管理和查看 SQLite 数据库,例如DB Browser For sqlite

配置标识服务Configure Identity services

ConfigureServices中添加服务。典型模式是调用所有 Add{Service} 方法,然后调用所有 services.Configure{Service} 方法。

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddDbContext<ApplicationDbContext>(options =>
  4. options.UseSqlServer(
  5. Configuration.GetConnectionString("DefaultConnection")));
  6. services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
  7. .AddEntityFrameworkStores<ApplicationDbContext>();
  8. services.AddRazorPages();
  9. services.Configure<IdentityOptions>(options =>
  10. {
  11. // Password settings.
  12. options.Password.RequireDigit = true;
  13. options.Password.RequireLowercase = true;
  14. options.Password.RequireNonAlphanumeric = true;
  15. options.Password.RequireUppercase = true;
  16. options.Password.RequiredLength = 6;
  17. options.Password.RequiredUniqueChars = 1;
  18. // Lockout settings.
  19. options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
  20. options.Lockout.MaxFailedAccessAttempts = 5;
  21. options.Lockout.AllowedForNewUsers = true;
  22. // User settings.
  23. options.User.AllowedUserNameCharacters =
  24. "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
  25. options.User.RequireUniqueEmail = false;
  26. });
  27. services.ConfigureApplicationCookie(options =>
  28. {
  29. // Cookie settings
  30. options.Cookie.HttpOnly = true;
  31. options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
  32. options.LoginPath = "/Identity/Account/Login";
  33. options.AccessDeniedPath = "/Identity/Account/AccessDenied";
  34. options.SlidingExpiration = true;
  35. });
  36. }

前面突出显示的代码用默认选项值配置标识。服务通过依赖关系注入提供给应用程序。

通过调用 UseAuthentication来启用标识。UseAuthentication 将身份验证中间件添加到请求管道。

  1. public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
  2. {
  3. if (env.IsDevelopment())
  4. {
  5. app.UseDeveloperExceptionPage();
  6. app.UseDatabaseErrorPage();
  7. }
  8. else
  9. {
  10. app.UseExceptionHandler("/Error");
  11. app.UseHsts();
  12. }
  13. app.UseHttpsRedirection();
  14. app.UseStaticFiles();
  15. app.UseRouting();
  16. app.UseAuthentication();
  17. app.UseAuthorization();
  18. app.UseEndpoints(endpoints =>
  19. {
  20. endpoints.MapRazorPages();
  21. });
  22. }

模板生成的应用不使用授权包括 app.UseAuthorization 以确保在应用添加授权时,按正确的顺序添加。必须按前面的代码中所示的顺序调用 UseRoutingUseAuthenticationUseAuthorizationUseEndpoints

有关 IdentityOptionsStartup的详细信息,请参阅 IdentityOptions应用程序启动

基架注册、登录和注销Scaffold Register, Login, and LogOut

添加注册、登录和注销文件。按照基架标识操作,并使用授权说明生成本部分中所示的代码。

如果创建的项目的名称为WebApp1,请运行以下命令。否则,请使用 ApplicationDbContext的正确命名空间:

  1. dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
  2. dotnet aspnet-codegenerator identity -dc WebApp1.Data.ApplicationDbContext --files "Account.Register;Account.Login;Account.Logout"

PowerShell 使用分号作为命令分隔符。使用 PowerShell 时,请对文件列表中的分号进行转义,或将文件列表置于双引号中,如前面的示例所示。

有关基架标识的详细信息,请参阅使用授权将基架标识导入 Razor 项目

检查注册Examine Register

当用户单击 "注册" 链接时,将调用 RegisterModel.OnPostAsync 操作。用户是通过CreateAsync_userManager 对象创建的。_userManager 由依赖关系注入提供):

  1. public async Task<IActionResult> OnPostAsync(string returnUrl = null)
  2. {
  3. returnUrl = returnUrl ?? Url.Content("~/");
  4. ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync())
  5. .ToList();
  6. if (ModelState.IsValid)
  7. {
  8. var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
  9. var result = await _userManager.CreateAsync(user, Input.Password);
  10. if (result.Succeeded)
  11. {
  12. _logger.LogInformation("User created a new account with password.");
  13. var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
  14. code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
  15. var callbackUrl = Url.Page(
  16. "/Account/ConfirmEmail",
  17. pageHandler: null,
  18. values: new { area = "Identity", userId = user.Id, code = code },
  19. protocol: Request.Scheme);
  20. await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
  21. $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
  22. if (_userManager.Options.SignIn.RequireConfirmedAccount)
  23. {
  24. return RedirectToPage("RegisterConfirmation",
  25. new { email = Input.Email });
  26. }
  27. else
  28. {
  29. await _signInManager.SignInAsync(user, isPersistent: false);
  30. return LocalRedirect(returnUrl);
  31. }
  32. }
  33. foreach (var error in result.Errors)
  34. {
  35. ModelState.AddModelError(string.Empty, error.Description);
  36. }
  37. }
  38. // If we got this far, something failed, redisplay form
  39. return Page();
  40. }

如果已成功创建用户,则会通过调用 _signInManager.SignInAsync登录该用户。

请参阅帐户确认以了解在注册时要阻止立即登录的步骤。

登录Log in

发生下列情况时,会显示登录窗体:

  • 选择 "登录" 链接。
  • 用户尝试访问他们无权访问的受限制的页面,未经系统的身份验证。

提交登录页上的窗体时,将调用 OnPostAsync 操作。_signInManager 对象(由依赖关系注入提供)调用 PasswordSignInAsync

  1. public async Task<IActionResult> OnPostAsync(string returnUrl = null)
  2. {
  3. returnUrl = returnUrl ?? Url.Content("~/");
  4. if (ModelState.IsValid)
  5. {
  6. // This doesn't count login failures towards account lockout
  7. // To enable password failures to trigger account lockout,
  8. // set lockoutOnFailure: true
  9. var result = await _signInManager.PasswordSignInAsync(Input.Email,
  10. Input.Password, Input.RememberMe, lockoutOnFailure: true);
  11. if (result.Succeeded)
  12. {
  13. _logger.LogInformation("User logged in.");
  14. return LocalRedirect(returnUrl);
  15. }
  16. if (result.RequiresTwoFactor)
  17. {
  18. return RedirectToPage("./LoginWith2fa", new
  19. {
  20. ReturnUrl = returnUrl,
  21. RememberMe = Input.RememberMe
  22. });
  23. }
  24. if (result.IsLockedOut)
  25. {
  26. _logger.LogWarning("User account locked out.");
  27. return RedirectToPage("./Lockout");
  28. }
  29. else
  30. {
  31. ModelState.AddModelError(string.Empty, "Invalid login attempt.");
  32. return Page();
  33. }
  34. }
  35. // If we got this far, something failed, redisplay form
  36. return Page();
  37. }

Base Controller 类公开可从控制器方法访问的 User 属性。例如,可以枚举 User.Claims 并做出授权决策。有关详细信息,请参阅 在 ASP.NET Core 中授权简介

注销Log out

"注销" 链接调用 LogoutModel.OnPost 操作。

  1. using Microsoft.AspNetCore.Authorization;
  2. using Microsoft.AspNetCore.Identity;
  3. using Microsoft.AspNetCore.Mvc;
  4. using Microsoft.AspNetCore.Mvc.RazorPages;
  5. using Microsoft.Extensions.Logging;
  6. using System.Threading.Tasks;
  7. namespace WebApp1.Areas.Identity.Pages.Account
  8. {
  9. [AllowAnonymous]
  10. public class LogoutModel : PageModel
  11. {
  12. private readonly SignInManager<IdentityUser> _signInManager;
  13. private readonly ILogger<LogoutModel> _logger;
  14. public LogoutModel(SignInManager<IdentityUser> signInManager, ILogger<LogoutModel> logger)
  15. {
  16. _signInManager = signInManager;
  17. _logger = logger;
  18. }
  19. public void OnGet()
  20. {
  21. }
  22. public async Task<IActionResult> OnPost(string returnUrl = null)
  23. {
  24. await _signInManager.SignOutAsync();
  25. _logger.LogInformation("User logged out.");
  26. if (returnUrl != null)
  27. {
  28. return LocalRedirect(returnUrl);
  29. }
  30. else
  31. {
  32. return RedirectToPage();
  33. }
  34. }
  35. }
  36. }

在前面的代码中,代码 return RedirectToPage(); 需要是重定向,以便浏览器执行新请求并更新用户的标识。

SignOutAsync清除 cookie 中存储的用户声明。

Post 在Pages/Shared/_LoginPartial 中指定。 cshtml

  1. @using Microsoft.AspNetCore.Identity
  2. @inject SignInManager<IdentityUser> SignInManager
  3. @inject UserManager<IdentityUser> UserManager
  4. <ul class="navbar-nav">
  5. @if (SignInManager.IsSignedIn(User))
  6. {
  7. <li class="nav-item">
  8. <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index"
  9. title="Manage">Hello @User.Identity.Name!</a>
  10. </li>
  11. <li class="nav-item">
  12. <form class="form-inline" asp-area="Identity" asp-page="/Account/Logout"
  13. asp-route-returnUrl="@Url.Page("/", new { area = "" })"
  14. method="post" >
  15. <button type="submit" class="nav-link btn btn-link text-dark">Logout</button>
  16. </form>
  17. </li>
  18. }
  19. else
  20. {
  21. <li class="nav-item">
  22. <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Register">Register</a>
  23. </li>
  24. <li class="nav-item">
  25. <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Login">Login</a>
  26. </li>
  27. }
  28. </ul>

测试标识Test Identity

默认 web 项目模板允许匿名访问主页。若要测试标识,请添加[Authorize]

  1. using Microsoft.AspNetCore.Authorization;
  2. using Microsoft.AspNetCore.Mvc.RazorPages;
  3. using Microsoft.Extensions.Logging;
  4. namespace WebApp1.Pages
  5. {
  6. [Authorize]
  7. public class PrivacyModel : PageModel
  8. {
  9. private readonly ILogger<PrivacyModel> _logger;
  10. public PrivacyModel(ILogger<PrivacyModel> logger)
  11. {
  12. _logger = logger;
  13. }
  14. public void OnGet()
  15. {
  16. }
  17. }
  18. }

如果已登录,请注销。运行应用并选择 "隐私" 链接。将被重定向到登录页。

浏览标识Explore Identity

更详细地了解标识:

标识组件Identity Components

所有标识相关 NuGet 包都包含在ASP.NET Core 共享框架中。

标识的主包为AspNetCore此程序包包含用于 ASP.NET Core 标识的核心接口集,由 Microsoft.AspNetCore.Identity.EntityFrameworkCore包含。

迁移到 ASP.NET Core 标识Migrating to ASP.NET Core Identity

有关迁移现有标识存储的详细信息和指南,请参阅迁移身份验证和标识

设置密码强度Setting password strength

有关设置最小密码要求的示例,请参阅配置

AddDefaultIdentity 和 AddIdentityAddDefaultIdentity and AddIdentity

AddDefaultIdentity 是在 ASP.NET Core 2.1 中引入的。调用 AddDefaultIdentity 类似于调用以下内容:

有关详细信息,请参阅AddDefaultIdentity 源

禁止发布静态标识资产Prevent publish of static Identity assets

若要防止将静态标识资产(用于标识 UI 的样式表和 JavaScript 文件)发布到 web 根目录,请将以下 ResolveStaticWebAssetsInputsDependsOn 属性和 RemoveIdentityAssets 目标添加到应用的项目文件中:

  1. <PropertyGroup>
  2. <ResolveStaticWebAssetsInputsDependsOn>RemoveIdentityAssets</ResolveStaticWebAssetsInputsDependsOn>
  3. </PropertyGroup>
  4. <Target Name="RemoveIdentityAssets">
  5. <ItemGroup>
  6. <StaticWebAsset Remove="@(StaticWebAsset)" Condition="%(SourceId) == 'Microsoft.AspNetCore.Identity.UI'" />
  7. </ItemGroup>
  8. </Target>

后续步骤Next Steps

作者:Rick Anderson

ASP.NET Core 标识是将登录功能添加到 ASP.NET Core 应用的成员资格系统。用户可以创建一个具有存储在标识中的登录信息的帐户,也可以使用外部登录提供程序。支持的外部登录提供程序包括Facebook、Google、Microsoft 帐户和 Twitter

可以使用 SQL Server 数据库配置标识,以存储用户名、密码和配置文件数据。另外,还可以使用另一个永久性存储,例如 Azure 表存储。

查看或下载示例代码如何下载)

本主题介绍如何使用标识注册、登录和注销用户。有关创建使用标识的应用的更多详细说明,请参阅本文末尾的后续步骤部分。

AddDefaultIdentity 和 AddIdentityAddDefaultIdentity and AddIdentity

AddDefaultIdentity 是在 ASP.NET Core 2.1 中引入的。调用 AddDefaultIdentity 类似于调用以下内容:

有关详细信息,请参阅AddDefaultIdentity 源

创建具有身份验证的 Web 应用Create a Web app with authentication

使用单个用户帐户创建一个 ASP.NET Core Web 应用程序项目。

  • 选择 "文件" >新建>项目"。
  • 选择“ASP.NET Core Web 应用程序”。将项目命名为WebApp1 ,使其命名空间与项目下载相同。单击“确定”。
  • 选择 ASP.NET Core Web 应用程序,然后选择 "更改身份验证"。
  • 选择单个用户帐户,然后单击 "确定"
  1. dotnet new webapp --auth Individual -o WebApp1

生成的项目提供ASP.NET Core 标识作为Razor 类库标识 Razor 类库公开 Identity 区域的终结点。例如:

  • /Identity/Account/Login
  • /Identity/Account/Logout
  • /Identity/Account/Manage

应用迁移Apply migrations

应用迁移以初始化数据库。

在包管理器控制台中运行以下命令(PMC):

  1. Update-Database
  1. dotnet ef database update

测试注册和登录Test Register and Login

运行应用并注册用户。根据屏幕大小,你可能需要选择 "导航" 切换按钮以查看 "寄存器" 和 "登录" 链接。

查看标识数据库View the Identity database

  • 从 "视图" 菜单中选择 " SQL Server 对象资源管理器" (SSOX)。
  • 导航到 (localdb) MSSQLLocalDB (SQL Server 13) 。右键单击 " dbo"。AspNetUsers > 查看数据

SQL Server 对象资源管理器中的 AspNetUsers 表上的上下文菜单

您可以下载许多第三方工具来管理和查看 SQLite 数据库,例如DB Browser For sqlite

配置标识服务Configure Identity services

ConfigureServices中添加服务。典型模式是调用所有 Add{Service} 方法,然后调用所有 services.Configure{Service} 方法。

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.Configure<CookiePolicyOptions>(options =>
  4. {
  5. options.CheckConsentNeeded = context => true;
  6. options.MinimumSameSitePolicy = SameSiteMode.None;
  7. });
  8. services.AddDbContext<ApplicationDbContext>(options =>
  9. options.UseSqlServer(
  10. Configuration.GetConnectionString("DefaultConnection")));
  11. services.AddDefaultIdentity<IdentityUser>()
  12. .AddDefaultUI(UIFramework.Bootstrap4)
  13. .AddEntityFrameworkStores<ApplicationDbContext>();
  14. services.Configure<IdentityOptions>(options =>
  15. {
  16. // Password settings.
  17. options.Password.RequireDigit = true;
  18. options.Password.RequireLowercase = true;
  19. options.Password.RequireNonAlphanumeric = true;
  20. options.Password.RequireUppercase = true;
  21. options.Password.RequiredLength = 6;
  22. options.Password.RequiredUniqueChars = 1;
  23. // Lockout settings.
  24. options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
  25. options.Lockout.MaxFailedAccessAttempts = 5;
  26. options.Lockout.AllowedForNewUsers = true;
  27. // User settings.
  28. options.User.AllowedUserNameCharacters =
  29. "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
  30. options.User.RequireUniqueEmail = false;
  31. });
  32. services.ConfigureApplicationCookie(options =>
  33. {
  34. // Cookie settings
  35. options.Cookie.HttpOnly = true;
  36. options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
  37. options.LoginPath = "/Identity/Account/Login";
  38. options.AccessDeniedPath = "/Identity/Account/AccessDenied";
  39. options.SlidingExpiration = true;
  40. });
  41. services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
  42. }

前面的代码用默认选项值配置标识。服务通过依赖关系注入提供给应用程序。

通过调用UseAuthentication来启用标识。UseAuthentication 将身份验证中间件添加到请求管道。

  1. public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  2. {
  3. if (env.IsDevelopment())
  4. {
  5. app.UseDeveloperExceptionPage();
  6. app.UseDatabaseErrorPage();
  7. }
  8. else
  9. {
  10. app.UseExceptionHandler("/Error");
  11. app.UseHsts();
  12. }
  13. app.UseHttpsRedirection();
  14. app.UseStaticFiles();
  15. app.UseCookiePolicy();
  16. app.UseAuthentication();
  17. app.UseMvc();
  18. }

有关详细信息,请参阅IdentityOptions 类应用程序启动

基架注册、登录和注销Scaffold Register, Login, and LogOut

按照基架标识操作,并使用授权说明生成本部分中所示的代码。

添加注册、登录和注销文件。

如果创建的项目的名称为WebApp1,请运行以下命令。否则,请使用 ApplicationDbContext的正确命名空间:

  1. dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
  2. dotnet aspnet-codegenerator identity -dc WebApp1.Data.ApplicationDbContext --files "Account.Register;Account.Login;Account.Logout"

PowerShell 使用分号作为命令分隔符。使用 PowerShell 时,请对文件列表中的分号进行转义,或将文件列表置于双引号中,如前面的示例所示。

检查注册Examine Register

当用户单击 "注册" 链接时,将调用 RegisterModel.OnPostAsync 操作。用户是通过CreateAsync_userManager 对象创建的。_userManager 由依赖关系注入提供):

  1. public async Task<IActionResult> OnPostAsync(string returnUrl = null)
  2. {
  3. returnUrl = returnUrl ?? Url.Content("~/");
  4. if (ModelState.IsValid)
  5. {
  6. var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
  7. var result = await _userManager.CreateAsync(user, Input.Password);
  8. if (result.Succeeded)
  9. {
  10. _logger.LogInformation("User created a new account with password.");
  11. var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
  12. var callbackUrl = Url.Page(
  13. "/Account/ConfirmEmail",
  14. pageHandler: null,
  15. values: new { userId = user.Id, code = code },
  16. protocol: Request.Scheme);
  17. await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
  18. $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
  19. await _signInManager.SignInAsync(user, isPersistent: false);
  20. return LocalRedirect(returnUrl);
  21. }
  22. foreach (var error in result.Errors)
  23. {
  24. ModelState.AddModelError(string.Empty, error.Description);
  25. }
  26. }
  27. // If we got this far, something failed, redisplay form
  28. return Page();
  29. }

如果已成功创建用户,则会通过调用 _signInManager.SignInAsync登录该用户。

注意: 请参阅帐户确认以了解在注册时要阻止立即登录的步骤。

登录Log in

发生下列情况时,会显示登录窗体:

  • 选择 "登录" 链接。
  • 用户尝试访问他们无权访问的受限制的页面,未经系统的身份验证。

提交登录页上的窗体时,将调用 OnPostAsync 操作。_signInManager 对象(由依赖关系注入提供)调用 PasswordSignInAsync

  1. public async Task<IActionResult> OnPostAsync(string returnUrl = null)
  2. {
  3. returnUrl = returnUrl ?? Url.Content("~/");
  4. if (ModelState.IsValid)
  5. {
  6. // This doesn't count login failures towards account lockout
  7. // To enable password failures to trigger account lockout,
  8. // set lockoutOnFailure: true
  9. var result = await _signInManager.PasswordSignInAsync(Input.Email,
  10. Input.Password, Input.RememberMe, lockoutOnFailure: true);
  11. if (result.Succeeded)
  12. {
  13. _logger.LogInformation("User logged in.");
  14. return LocalRedirect(returnUrl);
  15. }
  16. if (result.RequiresTwoFactor)
  17. {
  18. return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe });
  19. }
  20. if (result.IsLockedOut)
  21. {
  22. _logger.LogWarning("User account locked out.");
  23. return RedirectToPage("./Lockout");
  24. }
  25. else
  26. {
  27. ModelState.AddModelError(string.Empty, "Invalid login attempt.");
  28. return Page();
  29. }
  30. }
  31. // If we got this far, something failed, redisplay form
  32. return Page();
  33. }

Base Controller 类公开可从控制器方法访问的 User 属性。例如,可以枚举 User.Claims 并做出授权决策。有关详细信息,请参阅 在 ASP.NET Core 中授权简介

注销Log out

"注销" 链接调用 LogoutModel.OnPost 操作。

  1. using Microsoft.AspNetCore.Authorization;
  2. using Microsoft.AspNetCore.Identity;
  3. using Microsoft.AspNetCore.Mvc;
  4. using Microsoft.AspNetCore.Mvc.RazorPages;
  5. using Microsoft.Extensions.Logging;
  6. using System.Threading.Tasks;
  7. namespace WebApp1.Areas.Identity.Pages.Account
  8. {
  9. [AllowAnonymous]
  10. public class LogoutModel : PageModel
  11. {
  12. private readonly SignInManager<IdentityUser> _signInManager;
  13. private readonly ILogger<LogoutModel> _logger;
  14. public LogoutModel(SignInManager<IdentityUser> signInManager, ILogger<LogoutModel> logger)
  15. {
  16. _signInManager = signInManager;
  17. _logger = logger;
  18. }
  19. public void OnGet()
  20. {
  21. }
  22. public async Task<IActionResult> OnPost(string returnUrl = null)
  23. {
  24. await _signInManager.SignOutAsync();
  25. _logger.LogInformation("User logged out.");
  26. if (returnUrl != null)
  27. {
  28. return LocalRedirect(returnUrl);
  29. }
  30. else
  31. {
  32. // This needs to be a redirect so that the browser performs a new
  33. // request and the identity for the user gets updated.
  34. return RedirectToPage();
  35. }
  36. }
  37. }
  38. }

SignOutAsync清除 cookie 中存储的用户声明。

Post 在Pages/Shared/_LoginPartial 中指定。 cshtml

  1. @using Microsoft.AspNetCore.Identity
  2. @inject SignInManager<IdentityUser> SignInManager
  3. @inject UserManager<IdentityUser> UserManager
  4. <ul class="navbar-nav">
  5. @if (SignInManager.IsSignedIn(User))
  6. {
  7. <li class="nav-item">
  8. <a class="nav-link text-dark" asp-area="Identity"
  9. asp-page="/Account/Manage/Index"
  10. title="Manage">Hello@User.Identity.Name!</a>
  11. </li>
  12. <li class="nav-item">
  13. <form class="form-inline" asp-area="Identity" asp-page="/Account/Logout"
  14. asp-route-returnUrl="@Url.Page("/", new { area = "" })"
  15. method="post">
  16. <button type="submit" class="nav-link btn btn-link text-dark">Logout</button>
  17. </form>
  18. </li>
  19. }
  20. else
  21. {
  22. <li class="nav-item">
  23. <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Register">Register</a>
  24. </li>
  25. <li class="nav-item">
  26. <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Login">Login</a>
  27. </li>
  28. }
  29. </ul>

测试标识Test Identity

默认 web 项目模板允许匿名访问主页。若要测试标识,请将[Authorize]添加到 "隐私" 页。

  1. using Microsoft.AspNetCore.Authorization;
  2. using Microsoft.AspNetCore.Mvc.RazorPages;
  3. namespace WebApp1.Pages
  4. {
  5. [Authorize]
  6. public class PrivacyModel : PageModel
  7. {
  8. public void OnGet()
  9. {
  10. }
  11. }
  12. }

如果已登录,请注销。运行应用并选择 "隐私" 链接。将被重定向到登录页。

浏览标识Explore Identity

更详细地了解标识:

标识组件Identity Components

所有标识相关 NuGet 包都包含在AspNetCore 元包中。

标识的主包为AspNetCore此程序包包含用于 ASP.NET Core 标识的核心接口集,由 Microsoft.AspNetCore.Identity.EntityFrameworkCore包含。

迁移到 ASP.NET Core 标识Migrating to ASP.NET Core Identity

有关迁移现有标识存储的详细信息和指南,请参阅迁移身份验证和标识

设置密码强度Setting password strength

有关设置最小密码要求的示例,请参阅配置

后续步骤Next Steps