ASP.NET Core Identity:
- UI(사용자 인터페이스) 로그인 기능을 지원하는 API입니다.
- 사용자, 암호, 프로필 데이터, 역할, 클레임, 토큰, 이메일 확인 등을 관리합니다.
사용자는 Identity에 저장된 로그인 정보를 사용하여 계정을 만들거나 외부 로그인 공급자를 사용할 수 있습니다. 지원되는 외부 로그인 공급자에는 Facebook, Google, Microsoft 계정 및 Twitter가 포함됩니다.
모든 사용자의 인증을 전역으로 요구하는 방법에 대한 자세한 내용은 인증된 사용자 요구를 참조하세요.
Identity 소스 코드는 GitHub에서 사용할 수 있습니다. Identity 를 스캐폴드하고 생성된 파일을 확인하여 Identity와의 템플릿 상호 작용을 검토합니다.
Identity는 일반적으로 SQL Server 데이터베이스를 사용하여 사용자 이름, 암호 및 프로필 데이터를 저장하도록 구성됩니다. 또는 다른 영구 저장소(예: Azure Table Storage)를 사용할 수 있습니다.
이 항목에서는 Identity를 사용하여 사용자를 등록, 로그인 및 로그아웃하는 방법을 알아봅니다. 참고: 템플릿은 사용자 이름과 이메일을 사용자에 대해 동일하게 처리합니다. Identity를 사용하는 앱을 만드는 방법에 대한 자세한 지침은 다음 단계를 참조하세요.
앱에 대한 자세한 내용은 Identity 및 설명서에서 Blazor 해당 인증을 따르는 문서를 참조하세요.Blazor
ASP.NET Core IdentityMicrosoft ID 플랫폼관련이 없습니다. Microsoft ID 플랫폼은 다음과 같습니다.
- Azure AD(Azure Active Directory) 개발자 플랫폼의 진화
- ASP.NET Core 앱의 인증 및 권한 부여를 위한 대체 ID 솔루션입니다.
ASP.NET Core Identity는 ASP.NET Core 웹앱에 UI(사용자 인터페이스) 로그인 기능을 추가합니다. 웹 API 및 SPA를 보호하려면 다음 중 하나를 사용합니다.
- Microsoft Entra ID
- Azure Active Directory B2C(Azure AD B2C)
- Duende Identity 서버
Duende Identity Server는 ASP.NET Core용 OpenID Connect 및 OAuth 2.0 프레임워크입니다. Duende Identity Server에서는 다음과 같은 보안 기능을 사용할 수 있습니다.
- AaaS(Authentication as a Service)
- 여러 응용 프로그램 유형에 대한 SSO(Single Sign-On/Off)
- API에 대한 액세스 제어
- 페더레이션 게이트웨이
Important
Duende Software에서 Duende Identity 서버의 프로덕션 사용에 대한 라이선스 요금 지불을 요구할 수 있습니다. 자세한 내용은 .NET 5의 ASP.NET Core에서 .NET 6으로 마이그레이션을 참조하세요.
자세한 내용은 Duende Identity Server 설명서(Duende Software 웹 사이트)를 참조하세요.
인증을 사용하여 Blazor Web App 만들기
개별 계정으로 ASP.NET Core Blazor Web App 프로젝트를 만듭니다.
- Blazor Web App 템플릿을 선택하십시오. 다음을 선택합니다.
- 다음을 선택합니다.
- 인증 유형: 개별 계정
- 대화형 렌더링 모드: 서버
- 대화형 위치: 전역
- 선택하고생성합니다.
생성된 프로젝트에는 IdentityRazor 구성 요소가 포함됩니다. 구성 요소는 Components/Account 서버 프로젝트의 폴더에 있습니다. 다음은 그 예입니다.
Components/Account/Pages/Register.razorComponents/Account/Pages/Login.razorComponents/Account/Pages/Manage/ChangePassword.razor
Identity
Razor 구성 요소는 특정 사용 사례에 대한 설명서에서 개별적으로 설명되며 각 릴리스를 변경할 수 있습니다. 개별 계정을 사용하여 Blazor Web App를 생성하면, 생성된 프로젝트에 IdentityRazor 구성 요소가 포함됩니다.
Identity
Razor 구성 요소는 dotnet/aspnetcore 검사 할 수도 있습니다.
Note
문서 링크는 .NET 참조 소스를 가리키며, 일반적으로 저장소의 기본 브랜치를 로드합니다. 이는 .NET의 다음 릴리스를 위한 현재 개발 상태를 나타냅니다. 특정 릴리스를 위한 태그를 선택하려면 Switch branches or tags 드롭다운 목록을 사용하세요. 자세한 내용은 ASP.NET Core 소스 코드(dotnet/AspNetCore.Docs #26205)의 버전 태그를 선택하는 방법을 참조하세요.
자세한 내용은 ASP.NET Core Blazor 인증 및 권한 부여 및 설명서에서 Blazor 해당 인증을 따르는 문서를 참조하세요. 주요 ASP.NET Core 설명서 집합의 보안 및 Identity 영역에 있는 대부분의 문서가 앱에 Blazor 적용됩니다. 그러나 Blazor 설명서 집합에는 정보를 대체하거나 추가하는 문서와 지침이 포함되어 있습니다. 먼저 일반적인 ASP.NET Core 설명서 집합을 연구한 다음 Blazor 설명서의 Identity 문서에 액세스하는 것이 좋습니다.
인증을 사용하여 Razor Pages 앱 만들기
개별 계정을 사용하여 ASP.NET Core Web Application(Razor Pages) 프로젝트를 만듭니다.
- ASP.NET Core Web App(Razor페이지) 템플릿을 선택합니다. 다음을 선택합니다.
- 인증 유형에 대해 개별 계정을 선택합니다.
- 선택하고생성합니다.
생성된 프로젝트는 ASP.NET Core Identity 를 Razor RCL(클래스 라이브러리)로 제공합니다. 클래스 라이브러리는 Identity 영역의 RazorIdentity 엔드포인트를 노출합니다. 다음은 그 예입니다.
Areas/Identity/Pages/Account/RegisterAreas/Identity/Pages/Account/LoginAreas/Identity/Pages/Account/Manage/ChangePassword
페이지는 특정 사용 사례에 대한 설명서에서 개별적으로 설명되며 각 릴리스마다 변경될 수 있습니다. RCL의 모든 페이지를 보려면 ASP.NET Core 참조 원본(dotnet/aspnetcore GitHub 리포지토리, Identity/UI/src/Areas/Identity/Pages 폴더)을 참조하세요. 개별 페이지 또는 모든 페이지를 앱에 스캐폴드 할 수 있습니다. 자세한 내용은 ASP.NET Core 프로젝트에서 Identity 스캐폴드를 참조하세요.
인증을 사용하여 MVC 앱 만들기
개별 계정으로 ASP.NET Core MVC 프로젝트를 만듭니다.
- ASP.NET Core Web App(Model-View-Controller) 템플릿을 선택합니다. 다음을 선택합니다.
- 인증 유형에 대해 개별 계정을 선택합니다.
- 선택하고생성합니다.
생성된 프로젝트는 ASP.NET Core Identity 를 Razor RCL(클래스 라이브러리)로 제공합니다. 클래스 라이브러리는 IdentityRazor Pages를 기반으로 하고, Razor 영역과 함께 엔드포인트를 노출합니다. 다음은 그 예입니다.
Areas/Identity/Pages/Account/RegisterAreas/Identity/Pages/Account/LoginAreas/Identity/Pages/Account/Manage/ChangePassword
페이지는 특정 사용 사례에 대한 설명서에서 개별적으로 설명되며 각 릴리스마다 변경될 수 있습니다. RCL의 모든 페이지를 보려면 ASP.NET Core 참조 원본(dotnet/aspnetcore GitHub 리포지토리, Identity/UI/src/Areas/Identity/Pages 폴더)을 참조하세요. 개별 페이지 또는 모든 페이지를 앱에 스캐폴드 할 수 있습니다. 자세한 내용은 ASP.NET Core 프로젝트에서 Identity 스캐폴드를 참조하세요.
마이그레이션 적용
마이그레이션을 적용하여 데이터베이스를 초기화합니다.
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 및 애플리케이션 시작을 참조하세요.
사용자 등록, 로그인, 로그아웃 및 등록 확인 스캐폴드
Register, Login, LogOut 및 RegisterConfirmation 파일을 추가합니다. 권한 지침에 따라
레지스터 검사
사용자가 페이지에서 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는 테스트용으로만 사용되며 제작 앱에서 자동 계정 확인을 사용하지 않도록 설정해야 합니다.
확인 계정을 요구하고 등록 시 즉각 로그인을 방지하려면 DisplayConfirmAccountLink = false에서 /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs를 설정합니다.
[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(); 코드는 브라우저가 새 요청을 수행하고 사용자의 ID가 업데이트되도록 리디렉션이어야 합니다.
SignOutAsync에 저장된 사용자의 주장 데이터를 cookie에서 지웁니다.
게시물이 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 테스트
기본 웹 프로젝트 템플릿을 사용하면 홈 페이지에 익명으로 액세스할 수 있습니다.
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에 의해 포함됩니다.
ASP.NET Core Identity 마이그레이션
기존 Identity 저장소 마이그레이션에 대한 자세한 내용 및 지침은 인증 및 Identity 마이그레이션을 참조하세요.
암호 강도 설정
최소 암호 요구 사항을 설정하는 샘플은 구성을 참조하세요.
AddDefaultIdentity 및 AddIdentity
AddDefaultIdentity는 ASP.NET Core 2.1에서 도입되었습니다.
AddDefaultIdentity를 호출하는 것은 다음을 호출하는 것과 비슷합니다.
자세한 내용은 AddDefaultIdentity 원본을 참조하세요.
정적 Identity 자산 게시 방지
정적 Identity 자산(Identity UI용 스타일시트 및 JavaScript 파일)을 웹 루트에 게시하지 않도록 하려면 다음 ResolveStaticWebAssetsInputsDependsOn 속성 및 RemoveIdentityAssets 대상을 앱의 프로젝트 파일에 추가합니다.
<PropertyGroup>
<ResolveStaticWebAssetsInputsDependsOn>RemoveIdentityAssets</ResolveStaticWebAssetsInputsDependsOn>
</PropertyGroup>
<Target Name="RemoveIdentityAssets">
<ItemGroup>
<StaticWebAsset Remove="@(StaticWebAsset)" Condition="%(SourceId) == 'Microsoft.AspNetCore.Identity.UI'" />
</ItemGroup>
</Target>
다음 단계
- SQLite를 사용하여 구성하는 Identity 방법에 대한 자세한 내용은 SQLite에 대한 구성 Identity 방법(
dotnet/AspNetCore.Docs#5131)을 참조하세요. - Identity 구성
- 권한 부여로 보호된 사용자 데이터를 사용한 ASP.NET Core 앱 만들기
- ASP.NET Core 프로젝트에서 Identity에 사용자 데이터 추가, 다운로드 및 삭제
- ASP.NET Core에서 TOTP 인증 앱에 QR 코드 생성 사용
- ASP.NET Core로 인증 및 Identity 마이그레이션
- ASP.NET Core의 계정 확인 및 암호 복구
- ASP.NET Core의 다단계 인증
- 웹 팜에서 ASP.NET Core 호스트
작성자: Rick Anderson
ASP.NET Core Identity:
- UI(사용자 인터페이스) 로그인 기능을 지원하는 API입니다.
- 사용자, 암호, 프로필 데이터, 역할, 클레임, 토큰, 이메일 확인 등을 관리합니다.
사용자는 Identity에 저장된 로그인 정보를 사용하여 계정을 만들거나 외부 로그인 공급자를 사용할 수 있습니다. 지원되는 외부 로그인 공급자에는 Facebook, Google, Microsoft 계정 및 Twitter가 포함됩니다.
모든 사용자의 인증을 전역으로 요구하는 방법에 대한 자세한 내용은 인증된 사용자 요구를 참조하세요.
Identity 소스 코드는 GitHub에서 사용할 수 있습니다. Identity 를 스캐폴드하고 생성된 파일을 확인하여 Identity와의 템플릿 상호 작용을 검토합니다.
Identity는 일반적으로 SQL Server 데이터베이스를 사용하여 사용자 이름, 암호 및 프로필 데이터를 저장하도록 구성됩니다. 또는 다른 영구 저장소(예: Azure Table Storage)를 사용할 수 있습니다.
이 항목에서는 Identity를 사용하여 사용자를 등록, 로그인 및 로그아웃하는 방법을 알아봅니다. 참고: 템플릿은 사용자 이름과 이메일을 사용자에 대해 동일하게 처리합니다. Identity를 사용하는 앱을 만드는 방법에 대한 자세한 지침은 다음 단계를 참조하세요.
ASP.NET Core IdentityMicrosoft ID 플랫폼관련이 없습니다. Microsoft ID 플랫폼은 다음과 같습니다.
- Azure AD(Azure Active Directory) 개발자 플랫폼의 진화
- ASP.NET Core 앱의 인증 및 권한 부여를 위한 대체 ID 솔루션입니다.
ASP.NET Core Identity는 ASP.NET Core 웹앱에 UI(사용자 인터페이스) 로그인 기능을 추가합니다. 웹 API 및 SPA를 보호하려면 다음 중 하나를 사용합니다.
- Microsoft Entra ID
- Azure Active Directory B2C(Azure AD B2C)
- Duende Identity 서버
Duende Identity Server는 ASP.NET Core용 OpenID Connect 및 OAuth 2.0 프레임워크입니다. Duende Identity Server에서는 다음과 같은 보안 기능을 사용할 수 있습니다.
- AaaS(Authentication as a Service)
- 여러 응용 프로그램 유형에 대한 SSO(Single Sign-On/Off)
- API에 대한 액세스 제어
- 페더레이션 게이트웨이
Important
Duende Software에서 Duende Identity 서버의 프로덕션 사용에 대한 라이선스 요금 지불을 요구할 수 있습니다. 자세한 내용은 .NET 5의 ASP.NET Core에서 .NET 6으로 마이그레이션을 참조하세요.
자세한 내용은 Duende Identity Server 설명서(Duende Software 웹 사이트)를 참조하세요.
인증을 사용하여 웹앱 만들기
개별 사용자 계정을 사용하여 ASP.NET Core 웹 애플리케이션 프로젝트를 만듭니다.
- ASP.NET Core 웹앱 템플릿을 선택합니다. 프로젝트 이름을 WebApp1로 지정하여 프로젝트 다운로드와 동일한 네임스페이스를 갖습니다. OK를 클릭합니다.
- 인증 유형 입력에서 개별 사용자 계정을 선택합니다.
생성된 프로젝트는 ASP.NET CoreIdentity를 클래스 라이브러리로Razor 제공합니다. 클래스 라이브러리는 Identity 영역의 RazorIdentity 엔드포인트를 노출합니다. 다음은 그 예입니다.
- /Identity/계정/로그인
- /Identity/Account/Logout
- /Identity/계정/관리
마이그레이션 적용
마이그레이션을 적용하여 데이터베이스를 초기화합니다.
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 및 애플리케이션 시작을 참조하세요.
사용자 등록, 로그인, 로그아웃 및 등록 확인 스캐폴드
Register, Login, LogOut 및 RegisterConfirmation 파일을 추가합니다. 권한 지침에 따라
레지스터 검사
사용자가 페이지에서 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는 테스트용으로만 사용되며 제작 앱에서 자동 계정 확인을 사용하지 않도록 설정해야 합니다.
확인 계정을 요구하고 등록 시 즉각 로그인을 방지하려면 DisplayConfirmAccountLink = false에서 /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs를 설정합니다.
[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(); 코드는 브라우저가 새 요청을 수행하고 사용자의 ID가 업데이트되도록 리디렉션이어야 합니다.
SignOutAsync에 저장된 사용자의 주장 데이터를 cookie에서 지웁니다.
게시물이 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 테스트
기본 웹 프로젝트 템플릿을 사용하면 홈 페이지에 익명으로 액세스할 수 있습니다.
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에 의해 포함됩니다.
ASP.NET Core Identity 마이그레이션
기존 Identity 저장소 마이그레이션에 대한 자세한 내용 및 지침은 인증 및 Identity 마이그레이션을 참조하세요.
암호 강도 설정
최소 암호 요구 사항을 설정하는 샘플은 구성을 참조하세요.
AddDefaultIdentity 및 AddIdentity
AddDefaultIdentity는 ASP.NET Core 2.1에서 도입되었습니다.
AddDefaultIdentity를 호출하는 것은 다음을 호출하는 것과 비슷합니다.
자세한 내용은 AddDefaultIdentity 원본을 참조하세요.
정적 Identity 자산 게시 방지
정적 Identity 자산(Identity UI용 스타일시트 및 JavaScript 파일)을 웹 루트에 게시하지 않도록 하려면 다음 ResolveStaticWebAssetsInputsDependsOn 속성 및 RemoveIdentityAssets 대상을 앱의 프로젝트 파일에 추가합니다.
<PropertyGroup>
<ResolveStaticWebAssetsInputsDependsOn>RemoveIdentityAssets</ResolveStaticWebAssetsInputsDependsOn>
</PropertyGroup>
<Target Name="RemoveIdentityAssets">
<ItemGroup>
<StaticWebAsset Remove="@(StaticWebAsset)" Condition="%(SourceId) == 'Microsoft.AspNetCore.Identity.UI'" />
</ItemGroup>
</Target>
다음 단계
- SQLite를 사용하여 를 구성하는 방법에 대한 자세한 내용은 Identity를 참조하세요.
- Identity 구성
- 권한 부여로 보호된 사용자 데이터를 사용한 ASP.NET Core 앱 만들기
- ASP.NET Core 프로젝트에서 Identity에 사용자 데이터 추가, 다운로드 및 삭제
- ASP.NET Core에서 TOTP 인증 앱에 QR 코드 생성 사용
- ASP.NET Core로 인증 및 Identity 마이그레이션
- ASP.NET Core의 계정 확인 및 암호 복구
- ASP.NET Core에서 SMS를 사용한 2단계 인증
- 웹 팜에서 ASP.NET Core 호스트
작성자: Rick Anderson
ASP.NET Core Identity:
- UI(사용자 인터페이스) 로그인 기능을 지원하는 API입니다.
- 사용자, 암호, 프로필 데이터, 역할, 클레임, 토큰, 이메일 확인 등을 관리합니다.
사용자는 Identity에 저장된 로그인 정보를 사용하여 계정을 만들거나 외부 로그인 공급자를 사용할 수 있습니다. 지원되는 외부 로그인 공급자에는 Facebook, Google, Microsoft 계정 및 Twitter가 포함됩니다.
모든 사용자의 인증을 전역으로 요구하는 방법에 대한 자세한 내용은 인증된 사용자 요구를 참조하세요.
Identity 소스 코드는 GitHub에서 사용할 수 있습니다. Identity 를 스캐폴드하고 생성된 파일을 확인하여 Identity와의 템플릿 상호 작용을 검토합니다.
Identity는 일반적으로 SQL Server 데이터베이스를 사용하여 사용자 이름, 암호 및 프로필 데이터를 저장하도록 구성됩니다. 또는 다른 영구 저장소(예: Azure Table Storage)를 사용할 수 있습니다.
이 항목에서는 Identity를 사용하여 사용자를 등록, 로그인 및 로그아웃하는 방법을 알아봅니다. 참고: 템플릿은 사용자 이름과 이메일을 사용자에 대해 동일하게 처리합니다. Identity를 사용하는 앱을 만드는 방법에 대한 자세한 지침은 다음 단계를 참조하세요.
Microsoft ID 플랫폼 다음과 같습니다.
- Azure AD(Azure Active Directory) 개발자 플랫폼의 진화
- ASP.NET Core 앱의 인증 및 권한 부여를 위한 대체 ID 솔루션입니다.
- ASP.NET Core Identity관련이 없습니다.
ASP.NET Core Identity는 ASP.NET Core 웹앱에 UI(사용자 인터페이스) 로그인 기능을 추가합니다. 웹 API 및 SPA를 보호하려면 다음 중 하나를 사용합니다.
- Microsoft Entra ID
- Azure Active Directory B2C(Azure AD B2C)
- Duende IdentityServer. Duende IdentityServer는 타사 제품입니다.
Duende IdentityServer는 ASP.NET Core용 OpenID Connect 및 OAuth 2.0 프레임워크입니다. Duende IdentityServer를 사용하면 다음과 같은 보안 기능을 사용할 수 있습니다.
- AaaS(Authentication as a Service)
- 여러 응용 프로그램 유형에 대한 SSO(Single Sign-On/Off)
- API에 대한 액세스 제어
- 페더레이션 게이트웨이
자세한 내용은 Duende IdentityServer 개요를 참조 하세요.
다른 인증 공급자에 대한 자세한 내용은 ASP.NET Core 대한 커뮤니티 OSS 인증 옵션을 참조하세요.
인증을 사용하여 웹앱 만들기
개별 사용자 계정을 사용하여 ASP.NET Core 웹 애플리케이션 프로젝트를 만듭니다.
- 파일>새>프로젝트를 선택합니다.
- 새 ASP.NET Core 웹 애플리케이션을 선택합니다. 프로젝트 이름을 WebApp1로 지정하여 프로젝트 다운로드와 동일한 네임스페이스를 갖습니다. OK를 클릭합니다.
- ASP.NET Core 웹 애플리케이션을 선택한 다음, 인증 변경을 선택합니다.
- 개별 사용자 계정을 선택하고 확인을 클릭합니다.
생성된 프로젝트는 ASP.NET CoreIdentity를 클래스 라이브러리로Razor 제공합니다. 클래스 라이브러리는 Identity 영역의 RazorIdentity 엔드포인트를 노출합니다. 다음은 그 예입니다.
- /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는 이전 코드에 표시된 순서대로 호출되어야 합니다.
IdentityOptions 및 Startup에 대한 자세한 내용은 IdentityOptions 및 애플리케이션 시작을 참조하세요.
사용자 등록, 로그인, 로그아웃 및 등록 확인 스캐폴드
Register, Login, LogOut 및 RegisterConfirmation 파일을 추가합니다. 권한 지침에 따라
레지스터 검사
사용자가 페이지에서 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는 테스트용으로만 사용되며 제작 앱에서 자동 계정 확인을 사용하지 않도록 설정해야 합니다.
확인 계정을 요구하고 등록 시 즉각 로그인을 방지하려면 DisplayConfirmAccountLink = false에서 /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs를 설정합니다.
[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(); 코드는 브라우저가 새 요청을 수행하고 사용자의 ID가 업데이트되도록 리디렉션이어야 합니다.
SignOutAsync에 저장된 사용자의 주장 데이터를 cookie에서 지웁니다.
게시물이 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 테스트
기본 웹 프로젝트 템플릿을 사용하면 홈 페이지에 익명으로 액세스할 수 있습니다.
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에 의해 포함됩니다.
ASP.NET Core Identity 마이그레이션
기존 Identity 저장소 마이그레이션에 대한 자세한 내용 및 지침은 인증 및 Identity 마이그레이션을 참조하세요.
암호 강도 설정
최소 암호 요구 사항을 설정하는 샘플은 구성을 참조하세요.
정적 Identity 자산 게시 방지
정적 Identity 자산(Identity UI용 스타일시트 및 JavaScript 파일)을 웹 루트에 게시하지 않도록 하려면 다음 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 소스 코드
- AddDefaultIdentity 원본
- SQLite를 사용하여 를 구성하는 방법에 대한 자세한 내용은 Identity를 참조하세요.
- Identity 구성
- 권한 부여로 보호된 사용자 데이터를 사용한 ASP.NET Core 앱 만들기
- ASP.NET Core 프로젝트에서 Identity에 사용자 데이터 추가, 다운로드 및 삭제
- ASP.NET Core에서 TOTP 인증 앱에 QR 코드 생성 사용
- ASP.NET Core로 인증 및 Identity 마이그레이션
- ASP.NET Core의 계정 확인 및 암호 복구
- ASP.NET Core에서 SMS를 사용한 2단계 인증
- 웹 팜에서 ASP.NET Core 호스트
ASP.NET Core