Identity on ASP.NET Core 簡介
IdentityASP.NET Core :
- 這是支援使用者介面 (UI) 登入功能的 API。
- 管理使用者、密碼、設定檔資料、角色、宣告、權杖、電子郵件確認等等。
使用者可以使用儲存在 中的 Identity 登入資訊來建立帳戶,也可以使用外部登入提供者。 支援的外部登入提供者包括Facebook、Google、Microsoft 帳戶和 Twitter。
如需如何全域要求所有使用者通過驗證的資訊,請參閱 要求已驗證的使用者。
原始程式碼 Identity可在 GitHub 上取得。 支架 Identity並檢視產生的檔案,以檢閱與 的 Identity 範本互動。
Identity通常會使用SQL Server資料庫來設定,以儲存使用者名稱、密碼和設定檔資料。 或者,也可以使用另一個永續性存放區,例如 Azure 資料表儲存體。
在本主題中,您將瞭解如何使用 Identity 來註冊、登入和登出使用者。 注意:範本會將使用者名稱和電子郵件視為相同的使用者。 如需有關建立使用 Identity 之應用程式的詳細指示,請參閱 後續步驟。
IdentityASP.NET Core與Microsoft 身分識別平臺無關。 Microsoft 身分識別平臺為:
- Azure Active Directory (Azure AD) 開發人員平臺的演進。
- ASP.NET Core應用程式中驗證和授權的替代身分識別解決方案。
IdentityASP.NET Core會將使用者介面 (UI) 登入功能新增至 ASP.NET Core Web 應用程式。 若要保護 Web API 和 SPA,請使用下列其中一項:
- Azure Active Directory
- Azure Active Directory B2C (Azure AD B2C)
- IdentityServer4
IdentityServer4 是適用于 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 架構。 IdentityServer4 啟用下列安全性功能:
- 驗證即服務 (AaaS)
- 透過多個應用程式類型的單一登入/關閉 (SSO)
- API 的存取控制
- 同盟閘道
如需詳細資訊,請參閱 歡迎使用 Identity Server4。
檢視或下載範例程式碼 , (如何下載) 。
使用驗證建立 Web 應用程式
使用個別使用者帳戶建立 ASP.NET Core Web 應用程式專案。
- 選取 [ASP.NET Core Web 應用程式] 範本。 將專案命名為 WebApp1 ,其命名空間與專案下載相同。 按一下 [確定]。
- 在 [驗證類型] 輸入中,選取 [個別使用者帳戶]。
產生的專案會以類別庫的形式 Razor提供 ASP.NET Core Identity。 類別 IdentityRazor 庫會公開 Identity
具有區域的端點。 例如:
- / Identity /Account/Login
- / Identity /Account/Logout
- / Identity /Account/Manage
套用移轉
套用移轉以初始化資料庫。
在套件管理員主控台中執行下列命令, (PMC) :
Update-Database
測試註冊和登入
執行應用程式並註冊使用者。 視螢幕大小而定,您可能需要選取流覽切換按鈕,以查看 [註冊 ] 和 [ 登入] 連結。
檢視 Identity 資料庫
- 從 [檢視] 功能表中,選取[SQL Server 物件總管 ( SSOX) ]。
- 流覽至 (localdb) MSSQLLocalDB (SQL Server 13) 。 以滑鼠右鍵按一下dbo。AspNetUsers>檢視資料:
設定 Identity 服務
服務會在 中 Program.cs
新增。 典型的模式是以下列順序呼叫方法:
Add{Service}
builder.Services.Configure{Service}
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using WebApp1.Data;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.Configure<IdentityOptions>(options =>
{
// Password settings.
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireNonAlphanumeric = true;
options.Password.RequireUppercase = true;
options.Password.RequiredLength = 6;
options.Password.RequiredUniqueChars = 1;
// Lockout settings.
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.AllowedForNewUsers = true;
// User settings.
options.User.AllowedUserNameCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
options.User.RequireUniqueEmail = false;
});
builder.Services.ConfigureApplicationCookie(options =>
{
// Cookie settings
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
options.LoginPath = "/Identity/Account/Login";
options.AccessDeniedPath = "/Identity/Account/AccessDenied";
options.SlidingExpiration = true;
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
上述程式碼會 Identity 使用預設選項值進行設定。 服務可透過 相依性插入提供給應用程式。
Identity 會呼叫 UseAuthentication 來啟用 。 UseAuthentication
將驗證 中介軟體 新增至要求管線。
範本產生的應用程式不會使用 授權。 app.UseAuthorization
包含在內,以確保應用程式新增授權的順序正確。 UseRouting
、 UseAuthentication
和 UseAuthorization
必須依上述程式碼所示的順序呼叫。
如需 的詳細資訊 IdentityOptions
,請參閱 IdentityOptions 和 應用程式啟動。
Scaffold Register、Login、LogOut 和 RegisterConfirmation
Register
新增 、 Login
、 LogOut
和 RegisterConfirmation
檔案。 依照 Scaffold 身分識別進入 Razor 具有授權指示的專案 ,以產生本節中顯示的程式碼。
檢查暫存器
當使用者按一下頁面上的 [ 註冊 ] 按鈕 Register
時, RegisterModel.OnPostAsync
會叫用動作。 使用者是由 CreateAsync(TUser) 在 物件上 _userManager
建立:
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync())
.ToList();
if (ModelState.IsValid)
{
var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
var result = await _userManager.CreateAsync(user, Input.Password);
if (result.Succeeded)
{
_logger.LogInformation("User created a new account with password.");
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { area = "Identity", userId = user.Id, code = code },
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
if (_userManager.Options.SignIn.RequireConfirmedAccount)
{
return RedirectToPage("RegisterConfirmation",
new { email = Input.Email });
}
else
{
await _signInManager.SignInAsync(user, isPersistent: false);
return LocalRedirect(returnUrl);
}
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
// If we got this far, something failed, redisplay form
return Page();
}
停用預設帳戶驗證
使用預設範本時,系統會將使用者重新導向至 Account.RegisterConfirmation
可選取連結以確認帳戶的連結。 預設值 Account.RegisterConfirmation
僅用於 測試,生產應用程式中應該停用自動帳戶驗證。
若要要求已確認的帳戶,並防止在註冊時立即登入,請在 中 /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs
設定 DisplayConfirmAccountLink = false
:
[AllowAnonymous]
public class RegisterConfirmationModel : PageModel
{
private readonly UserManager<IdentityUser> _userManager;
private readonly IEmailSender _sender;
public RegisterConfirmationModel(UserManager<IdentityUser> userManager, IEmailSender sender)
{
_userManager = userManager;
_sender = sender;
}
public string Email { get; set; }
public bool DisplayConfirmAccountLink { get; set; }
public string EmailConfirmationUrl { get; set; }
public async Task<IActionResult> OnGetAsync(string email, string returnUrl = null)
{
if (email == null)
{
return RedirectToPage("/Index");
}
var user = await _userManager.FindByEmailAsync(email);
if (user == null)
{
return NotFound($"Unable to load user with email '{email}'.");
}
Email = email;
// Once you add a real email sender, you should remove this code that lets you confirm the account
DisplayConfirmAccountLink = false;
if (DisplayConfirmAccountLink)
{
var userId = await _userManager.GetUserIdAsync(user);
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
EmailConfirmationUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
protocol: Request.Scheme);
}
return Page();
}
}
登入
登入表單會在下列情況下顯示:
- 已選取 [ 登入 ] 連結。
- 使用者嘗試存取未獲授權存取的受限制頁面 ,或 系統尚未通過驗證時。
提交登入頁面上的表單時,會 OnPostAsync
呼叫動作。 PasswordSignInAsync
在 物件上 _signInManager
呼叫 。
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout,
// set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(Input.Email,
Input.Password, Input.RememberMe, lockoutOnFailure: true);
if (result.Succeeded)
{
_logger.LogInformation("User logged in.");
return LocalRedirect(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToPage("./LoginWith2fa", new
{
ReturnUrl = returnUrl,
RememberMe = Input.RememberMe
});
}
if (result.IsLockedOut)
{
_logger.LogWarning("User account locked out.");
return RedirectToPage("./Lockout");
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return Page();
}
}
// If we got this far, something failed, redisplay form
return Page();
}
如需如何做出授權決策的資訊,請參閱ASP.NET Core中的授權簡介。
登出
登出連結會叫用 LogoutModel.OnPost
動作。
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
namespace WebApp1.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class LogoutModel : PageModel
{
private readonly SignInManager<IdentityUser> _signInManager;
private readonly ILogger<LogoutModel> _logger;
public LogoutModel(SignInManager<IdentityUser> signInManager, ILogger<LogoutModel> logger)
{
_signInManager = signInManager;
_logger = logger;
}
public void OnGet()
{
}
public async Task<IActionResult> OnPost(string returnUrl = null)
{
await _signInManager.SignOutAsync();
_logger.LogInformation("User logged out.");
if (returnUrl != null)
{
return LocalRedirect(returnUrl);
}
else
{
return RedirectToPage();
}
}
}
}
在上述程式碼中,程式碼 return RedirectToPage();
必須是重新導向,讓瀏覽器執行新的要求,並更新使用者的身分識別。
SignOutAsync 清除儲存在 中的 cookie 使用者宣告。
Post 是在 中 Pages/Shared/_LoginPartial.cshtml
指定:
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
<ul class="navbar-nav">
@if (SignInManager.IsSignedIn(User))
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index"
title="Manage">Hello @User.Identity.Name!</a>
</li>
<li class="nav-item">
<form class="form-inline" asp-area="Identity" asp-page="/Account/Logout"
asp-route-returnUrl="@Url.Page("/", new { area = "" })"
method="post" >
<button type="submit" class="nav-link btn btn-link text-dark">Logout</button>
</form>
</li>
}
else
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Register">Register</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Login">Login</a>
</li>
}
</ul>
測試 Identity
預設 Web 專案範本允許匿名存取首頁。 若要測試 Identity ,請新增 [Authorize]
:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace WebApp1.Pages
{
[Authorize]
public class PrivacyModel : PageModel
{
private readonly ILogger<PrivacyModel> _logger;
public PrivacyModel(ILogger<PrivacyModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
}
}
如果您已登入,請登出。執行應用程式並選取 Privacy 連結。 系統會將您重新導向至 [登入] 頁面。
探討 Identity
若要更詳細地探索 Identity :
- 建立完整的身分識別 UI 來源
- 檢查每個頁面的來源,並逐步執行偵錯工具。
Identity 元件
Identity所有相依的 NuGet 套件都包含在ASP.NET Core共用架構中。
的主要套件 IdentityMicrosoft。AspNetCore. Identity. 此套件包含 ASP.NET Core Identity 的核心介面集,並由 包含 Microsoft.AspNetCore.Identity.EntityFrameworkCore
。
移轉至 ASP.NET Core Identity
如需移轉現有 Identity 存放區的詳細資訊和指引,請參閱移轉驗證和 Identity。
設定密碼強度
如需設定最低密碼需求的範例,請參閱設定。
AddDefault Identity 和 AddIdentity
AddDefaultIdentity已在 ASP.NET Core 2.1 中引進。 呼叫 AddDefaultIdentity
類似于呼叫下列專案:
如需詳細資訊,請參閱 AddDefault Identity 來源 。
防止發佈靜態 Identity 資產
若要防止將靜態 Identity 資產 (樣式表單和 JavaScript 檔案 Identity 發佈至 Web 根目錄) ,請將下列 ResolveStaticWebAssetsInputsDependsOn
屬性和 RemoveIdentityAssets
目標新增至應用程式的專案檔:
<PropertyGroup>
<ResolveStaticWebAssetsInputsDependsOn>RemoveIdentityAssets</ResolveStaticWebAssetsInputsDependsOn>
</PropertyGroup>
<Target Name="RemoveIdentityAssets">
<ItemGroup>
<StaticWebAsset Remove="@(StaticWebAsset)" Condition="%(SourceId) == 'Microsoft.AspNetCore.Identity.UI'" />
</ItemGroup>
</Target>
後續步驟
- IdentityASP.NET Core原始程式碼
- 如何在 ASP.NET Core !-- Identity<https://github.com/dotnet/AspNetCore.Docs/issues/7114 中使用角色 ->
- 如需使用 SQLite 進行設定 Identity 的詳細資訊,請參閱此 GitHub 問題。
- 設定 Identity
- 使用以授權機制保護的使用者資料來建立 ASP.NET Core 應用程式
- 在 ASP.NET Core專案中新增、下載和刪除使用者資料 Identity
- 在 ASP.NET Core 中啟用 TOTP 驗證器應用程式的 QR 代碼產生
- 將驗證和 Identity 移轉至 ASP.NET Core
- ASP.NET Core 中的帳戶確認和密碼復原
- 在 ASP.NET Core 中使用 SMS 進行雙因素驗證
- 在 Web 伺服陣列上裝載 ASP.NET Core
IdentityASP.NET Core:
- 這是支援使用者介面的 API (UI) 登入功能。
- 管理使用者、密碼、設定檔資料、角色、宣告、權杖、電子郵件確認等等。
使用者可以使用儲存在 中的 Identity 登入資訊來建立帳戶,也可以使用外部登入提供者。 支援的外部登入提供者包括Facebook、Google、Microsoft 帳戶和 Twitter。
如需如何全域要求所有使用者進行驗證的資訊,請參閱 要求已驗證的使用者。
Identity 原始程式碼可在 GitHub 上使用。 支架 Identity並檢視產生的檔案,以檢閱與 Identity 的範本互動。
Identity通常會使用SQL Server資料庫來設定,以儲存使用者名稱、密碼和設定檔資料。 或者,也可以使用另一個永續性存放區,例如 Azure 資料表儲存體。
在本主題中,您將瞭解如何使用 Identity 來註冊、登入和登出使用者。 注意:範本會將使用者名稱和電子郵件視為相同的使用者。 如需有關建立使用 Identity 之應用程式的詳細指示,請參閱 後續步驟。
- Azure Active Directory (Azure AD) 開發人員平臺的演進。
- ASP.NET Core應用程式中驗證和授權的替代身分識別解決方案。
- 與 ASP.NET Core Identity 無關。
IdentityASP.NET Core會將使用者介面 (UI) 登入功能新增至 ASP.NET Core Web 應用程式。 若要保護 Web API 和 SPA 的安全,請使用下列其中一項:
- Azure Active Directory
- Azure Active Directory B2C (Azure AD B2C)
- IdentityServer4
IdentityServer4 是適用于 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 架構。 IdentityServer4 啟用下列安全性功能:
- 驗證即服務 (AaaS)
- 單一登入/關閉 (SSO) 多個應用程式類型
- API 的存取控制
- 同盟閘道
如需詳細資訊,請參閱 歡迎使用 Identity Server4。
檢視或下載範例程式碼 (如何下載) 。
使用驗證建立 Web 應用程式
使用個別使用者帳戶建立 ASP.NET Core Web 應用程式專案。
- 選取 [File] \(檔案\)> [New] \(新增\)> [Project] \(專案\)。
- 選取 ASP.NET Core Web 應用程式。 將專案命名為 WebApp1 ,其命名空間與專案下載相同。 按一下 [確定]。
- 選取 ASP.NET Core Web 應用程式,然後選取[變更驗證]。
- 選取 [個別使用者帳戶 ],然後按一下 [ 確定]。
產生的專案會以類別庫的形式提供ASP.NET Core IdentityRazor。 類別 IdentityRazor 庫會公開具有 Identity
區域的端點。 例如:
- / Identity /Account/Login
- / Identity /Account/Logout
- / Identity /Account/Manage
套用移轉
套用移轉以初始化資料庫。
在套件管理員主控台中執行下列命令, (PMC) :
PM> Update-Database
測試註冊和登入
執行應用程式並註冊使用者。 視螢幕大小而定,您可能需要選取流覽切換按鈕,以查看 [註冊 ] 和 [ 登入] 連結。
檢視 Identity 資料庫
- 從 [檢視] 功能表中,選取[SQL Server 物件總管 ( SSOX) ]。
- 流覽至 (localdb) MSSQLLocalDB (SQL Server 13) 。 以滑鼠右鍵按一下dbo。AspNetUsers>檢視資料:
設定 Identity 服務
服務會在 中 ConfigureServices
新增。 典型模式是呼叫所有 Add{Service}
方法,然後呼叫 services.Configure{Service}
方法。
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
// options.UseSqlite(
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages();
services.Configure<IdentityOptions>(options =>
{
// Password settings.
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireNonAlphanumeric = true;
options.Password.RequireUppercase = true;
options.Password.RequiredLength = 6;
options.Password.RequiredUniqueChars = 1;
// Lockout settings.
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.AllowedForNewUsers = true;
// User settings.
options.User.AllowedUserNameCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
options.User.RequireUniqueEmail = false;
});
services.ConfigureApplicationCookie(options =>
{
// Cookie settings
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
options.LoginPath = "/Identity/Account/Login";
options.AccessDeniedPath = "/Identity/Account/AccessDenied";
options.SlidingExpiration = true;
});
}
上述醒目提示的程式碼會 Identity 使用預設選項值進行設定。 服務可透過 相依性插入提供給應用程式。
Identity 會呼叫 UseAuthentication 來啟用 。 UseAuthentication
將驗證 中介軟體 新增至要求管線。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
// options.UseSqlite(
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages();
services.Configure<IdentityOptions>(options =>
{
// Password settings.
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireNonAlphanumeric = true;
options.Password.RequireUppercase = true;
options.Password.RequiredLength = 6;
options.Password.RequiredUniqueChars = 1;
// Lockout settings.
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.AllowedForNewUsers = true;
// User settings.
options.User.AllowedUserNameCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
options.User.RequireUniqueEmail = false;
});
services.ConfigureApplicationCookie(options =>
{
// Cookie settings
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
options.LoginPath = "/Identity/Account/Login";
options.AccessDeniedPath = "/Identity/Account/AccessDenied";
options.SlidingExpiration = true;
});
}
上述程式碼會 Identity 使用預設選項值進行設定。 服務可透過 相依性插入提供給應用程式。
Identity 會呼叫 UseAuthentication 來啟用 。 UseAuthentication
將驗證 中介軟體 新增至要求管線。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
範本產生的應用程式不會使用 授權。 app.UseAuthorization
包含在內,以確保應用程式新增授權的順序正確。 UseRouting
、 UseAuthentication
、 UseAuthorization
和 UseEndpoints
必須依上述程式碼所示的順序呼叫。
如需 和 Startup
的詳細資訊 IdentityOptions
,請參閱 IdentityOptions 和應用程式啟動。
Scaffold Register、Login、LogOut 和 RegisterConfirmation
Register
新增 、 Login
、 LogOut
和 RegisterConfirmation
檔案。 依照 Scaffold 身分識別進入 Razor 具有授權指示的專案 ,以產生本節中顯示的程式碼。
檢查暫存器
當使用者按一下頁面上的 [ 註冊 ] 按鈕 Register
時, RegisterModel.OnPostAsync
會叫用動作。 使用者是由 CreateAsync(TUser) 在 物件上 _userManager
建立:
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync())
.ToList();
if (ModelState.IsValid)
{
var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
var result = await _userManager.CreateAsync(user, Input.Password);
if (result.Succeeded)
{
_logger.LogInformation("User created a new account with password.");
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { area = "Identity", userId = user.Id, code = code },
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
if (_userManager.Options.SignIn.RequireConfirmedAccount)
{
return RedirectToPage("RegisterConfirmation",
new { email = Input.Email });
}
else
{
await _signInManager.SignInAsync(user, isPersistent: false);
return LocalRedirect(returnUrl);
}
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
// If we got this far, something failed, redisplay form
return Page();
}
停用預設帳戶驗證
使用預設範本時,系統會將使用者重新導向至 Account.RegisterConfirmation
可選取連結以確認帳戶的連結。 預設值 Account.RegisterConfirmation
僅用於 測試,生產應用程式中應該停用自動帳戶驗證。
若要要求已確認的帳戶,並防止在註冊時立即登入,請在 中 /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs
設定 DisplayConfirmAccountLink = false
:
[AllowAnonymous]
public class RegisterConfirmationModel : PageModel
{
private readonly UserManager<IdentityUser> _userManager;
private readonly IEmailSender _sender;
public RegisterConfirmationModel(UserManager<IdentityUser> userManager, IEmailSender sender)
{
_userManager = userManager;
_sender = sender;
}
public string Email { get; set; }
public bool DisplayConfirmAccountLink { get; set; }
public string EmailConfirmationUrl { get; set; }
public async Task<IActionResult> OnGetAsync(string email, string returnUrl = null)
{
if (email == null)
{
return RedirectToPage("/Index");
}
var user = await _userManager.FindByEmailAsync(email);
if (user == null)
{
return NotFound($"Unable to load user with email '{email}'.");
}
Email = email;
// Once you add a real email sender, you should remove this code that lets you confirm the account
DisplayConfirmAccountLink = false;
if (DisplayConfirmAccountLink)
{
var userId = await _userManager.GetUserIdAsync(user);
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
EmailConfirmationUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
protocol: Request.Scheme);
}
return Page();
}
}
登入
登入表單會在下列情況下顯示:
- 已選取 [ 登入] 連結。
- 使用者嘗試存取未獲授權的受限制頁面, 或在 系統尚未通過驗證時存取。
提交登入頁面上的表單時,會 OnPostAsync
呼叫動作。 PasswordSignInAsync
在 _signInManager
物件上呼叫 。
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout,
// set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(Input.Email,
Input.Password, Input.RememberMe, lockoutOnFailure: true);
if (result.Succeeded)
{
_logger.LogInformation("User logged in.");
return LocalRedirect(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToPage("./LoginWith2fa", new
{
ReturnUrl = returnUrl,
RememberMe = Input.RememberMe
});
}
if (result.IsLockedOut)
{
_logger.LogWarning("User account locked out.");
return RedirectToPage("./Lockout");
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return Page();
}
}
// If we got this far, something failed, redisplay form
return Page();
}
如需如何做出授權決策的資訊,請參閱ASP.NET Core 中的授權簡介。
登出
登出連結會叫用 LogoutModel.OnPost
動作。
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
namespace WebApp1.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class LogoutModel : PageModel
{
private readonly SignInManager<IdentityUser> _signInManager;
private readonly ILogger<LogoutModel> _logger;
public LogoutModel(SignInManager<IdentityUser> signInManager, ILogger<LogoutModel> logger)
{
_signInManager = signInManager;
_logger = logger;
}
public void OnGet()
{
}
public async Task<IActionResult> OnPost(string returnUrl = null)
{
await _signInManager.SignOutAsync();
_logger.LogInformation("User logged out.");
if (returnUrl != null)
{
return LocalRedirect(returnUrl);
}
else
{
return RedirectToPage();
}
}
}
}
在上述程式碼中,程式碼 return RedirectToPage();
必須是重新導向,讓瀏覽器執行新的要求,並更新使用者的身分識別。
SignOutAsync 清除儲存在 中的 cookie 使用者宣告。
Post 是在 中 Pages/Shared/_LoginPartial.cshtml
指定:
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
<ul class="navbar-nav">
@if (SignInManager.IsSignedIn(User))
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index"
title="Manage">Hello @User.Identity.Name!</a>
</li>
<li class="nav-item">
<form class="form-inline" asp-area="Identity" asp-page="/Account/Logout"
asp-route-returnUrl="@Url.Page("/", new { area = "" })"
method="post" >
<button type="submit" class="nav-link btn btn-link text-dark">Logout</button>
</form>
</li>
}
else
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Register">Register</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Login">Login</a>
</li>
}
</ul>
測試 Identity
預設 Web 專案範本允許匿名存取首頁。 若要測試 Identity ,請新增 [Authorize]
:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace WebApp1.Pages
{
[Authorize]
public class PrivacyModel : PageModel
{
private readonly ILogger<PrivacyModel> _logger;
public PrivacyModel(ILogger<PrivacyModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
}
}
如果您已登入,請登出。執行應用程式並選取 Privacy 連結。 系統會將您重新導向至 [登入] 頁面。
探討 Identity
若要更詳細地探索 Identity :
- 建立完整的身分識別 UI 來源
- 檢查每個頁面的來源,並逐步執行偵錯工具。
Identity 元件
Identity所有相依 NuGet 套件都包含在ASP.NET Core共用架構中。
的主要套件 Identity 為Microsoft。AspNetCore. Identity. 此套件包含 ASP.NET Core Identity 的核心介面集,且 隨附于 Microsoft.AspNetCore.Identity.EntityFrameworkCore
。
移轉至 ASP.NET Core Identity
如需移轉現有 Identity 存放區的詳細資訊和指引,請參閱移轉驗證和 Identity。
設定密碼強度
如需設定最低密碼需求的範例,請參閱設定。
AddDefault Identity 和 AddIdentity
AddDefaultIdentity已在 ASP.NET Core 2.1 中引進。 呼叫 AddDefaultIdentity
類似于呼叫下列內容:
如需詳細資訊,請參閱 AddDefault Identity 來源 。
防止發佈靜態 Identity 資產
若要防止將靜態 Identity 資產發佈 (樣式表單和適用于 UI 的 JavaScript 檔案 Identity) 至 Web 根目錄,請將下列 ResolveStaticWebAssetsInputsDependsOn
屬性和 RemoveIdentityAssets
目標新增至應用程式的專案檔:
<PropertyGroup>
<ResolveStaticWebAssetsInputsDependsOn>RemoveIdentityAssets</ResolveStaticWebAssetsInputsDependsOn>
</PropertyGroup>
<Target Name="RemoveIdentityAssets">
<ItemGroup>
<StaticWebAsset Remove="@(StaticWebAsset)" Condition="%(SourceId) == 'Microsoft.AspNetCore.Identity.UI'" />
</ItemGroup>
</Target>
後續步驟
- ASP.NET Core Identity 原始程式碼
- 如需使用 SQLite 進行設定 Identity 的資訊,請參閱此 GitHub 問題。
- 設定 Identity
- 使用以授權機制保護的使用者資料來建立 ASP.NET Core 應用程式
- 在 ASP.NET Core專案中新增、下載和刪除使用者資料 Identity
- 在 ASP.NET Core 中啟用 TOTP 驗證器應用程式的 QR 代碼產生
- 將驗證和 Identity 移轉至 ASP.NET Core
- ASP.NET Core 中的帳戶確認和密碼復原
- 在 ASP.NET Core 中使用 SMS 進行雙因素驗證
- 在 Web 伺服陣列上裝載 ASP.NET Core