다음을 통해 공유


ASP.NET Core Identity 구성

ASP.NET Core Identity는 암호 정책, 잠금 및 cookie 구성과 같은 설정에 기본값을 사용합니다. 이러한 설정은 애플리케이션 시작 시 재정의할 수 있습니다.

Identity 옵션

IdentityOptions 클래스는 Identity 시스템을 구성하는 데 사용할 수 있는 옵션을 나타냅니다. AddIdentity 또는 AddDefaultIdentity를 호출한 IdentityOptions를 설정해야 합니다.

클레임 Identity

IdentityOptions.ClaimsIdentity는 다음 표에 표시된 속성을 사용하여 ClaimsIdentityOptions를 지정합니다.

속성 설명 기본값
RoleClaimType 역할 클레임에 사용되는 클레임 형식을 가져오거나 설정합니다. ClaimTypes.Role
SecurityStampClaimType 보안 스탬프 클레임에 사용되는 클레임 형식을 가져오거나 설정합니다. AspNet.Identity.SecurityStamp
UserIdClaimType 사용자 식별자 클레임에 사용되는 클레임 형식을 가져오거나 설정합니다. ClaimTypes.NameIdentifier
UserNameClaimType 사용자 이름 클레임에 사용되는 클레임 형식을 가져오거나 설정합니다. ClaimTypes.Name

잠금

잠금은 PasswordSignInAsync 메서드에서 설정합니다.

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl ??= Url.Content("~/");

    ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();

    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: false);
        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();
}

이전 코드는 LoginIdentity 템플릿을 기반으로 합니다.

잠금 옵션은 Program.cs에서 설정됩니다.

using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using RPauth.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 =>
{
    // Default Lockout settings.
    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
    options.Lockout.MaxFailedAccessAttempts = 5;
    options.Lockout.AllowedForNewUsers = 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();

앞의 코드는 기본값을 IdentityOptions LockoutOptions 설정합니다.

성공적인 인증은 실패한 액세스 시도 횟수를 다시 설정하고 시계를 다시 설정합니다.

IdentityOptions.Lockout 는 테이블에 표시된 속성을 사용하여 LockoutOptions를 지정합니다.

속성 설명 기본값
AllowedForNewUsers 새 사용자를 잠글 수 있는지 여부를 결정합니다. true
DefaultLockoutTimeSpan 잠금이 발생했을 때 사용자가 잠기는 시간입니다. 5분
MaxFailedAccessAttempts 잠금이 설정된 경우 사용자가 잠길 때까지 실패한 액세스 시도 횟수입니다. 5

암호

기본적으로 Identity에서는 암호에 대문자, 소문자, 숫자 및 영숫자가 아닌 문자를 포함해야 합니다. 암호 길이는 6자 이상이어야 합니다.

암호는 다음을 사용하여 구성됩니다.

  • Program.csPasswordOptions.
  • Identity가 앱에 스캐폴드된 경우 Password 속성의 [StringLength] 특성입니다. InputModelPassword 속성은 다음 파일에서 찾을 수 있습니다.
    • Areas/Identity/Pages/Account/Register.cshtml.cs
    • Areas/Identity/Pages/Account/ResetPassword.cshtml.cs
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using RPauth.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 =>
{
    // Default 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;
});

var app = builder.Build();

// Remaining code removed for brevity.

IdentityOptions.Password 는 테이블에 표시된 속성을 사용하여 PasswordOptions를 지정합니다.

속성 설명 기본값
RequireDigit 암호에 0-9 사이의 숫자가 필요합니다. true
RequiredLength 암호의 최소 길이입니다. 6
RequireLowercase 암호에 소문자가 필요합니다. true
RequireNonAlphanumeric 암호에 영숫자가 아닌 문자가 필요합니다. true
RequiredUniqueChars ASP.NET Core 2.0 이상에만 적용됩니다.

암호에 고유한 문자 수가 필요합니다.
1
RequireUppercase 암호에 대문자가 필요합니다. true

로그인

다음 코드는 SignIn 설정을 기본값으로 설정합니다.

builder.Services.Configure<IdentityOptions>(options =>
{
    // Default SignIn settings.
    options.SignIn.RequireConfirmedEmail = false;
    options.SignIn.RequireConfirmedPhoneNumber = false;
});

IdentityOptions.SignIn 는 테이블에 표시된 속성을 사용하여 SignInOptions를 지정합니다.

속성 설명 기본값
RequireConfirmedEmail 로그인하려면 확인된 이메일이 필요합니다. false
RequireConfirmedPhoneNumber 로그인하려면 확인된 전화 번호가 필요합니다. false

토큰

IdentityOptions.Tokens 는 테이블에 표시된 속성을 사용하여 TokenOptions를 지정합니다.

속성 설명
AuthenticatorTokenProvider 인증자를 사용하여 2단계 로그인의 유효성을 검사하는 데 사용되는 AuthenticatorTokenProvider를 가져오거나 설정합니다.
ChangeEmailTokenProvider 이메일 변경 확인 이메일에 사용되는 토큰을 생성하는 데 사용되는 ChangeEmailTokenProvider를 가져오거나 설정합니다.
ChangePhoneNumberTokenProvider 전화 번호를 변경할 때 사용되는 토큰을 생성하는 데 사용되는 ChangePhoneNumberTokenProvider를 가져오거나 설정합니다.
EmailConfirmationTokenProvider 계정 확인 이메일에 사용되는 토큰을 생성하는 데 사용되는 토큰 공급자를 가져오거나 설정합니다.
PasswordResetTokenProvider 암호 재설정 전자 메일에 사용되는 토큰을 생성하는 데 사용되는 IUserTwoFactorTokenProvider<TUser>를 가져오거나 설정합니다.
ProviderMap 공급자 이름으로 사용되는 키를 사용하여 사용자 토큰 공급자를 구성하는 데 사용됩니다.

사용자

builder.Services.Configure<IdentityOptions>(options =>
{
    // Default User settings.
    options.User.AllowedUserNameCharacters =
            "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
    options.User.RequireUniqueEmail = false;

});

IdentityOptions.User 는 테이블에 표시된 속성을 사용하여 UserOptions를 지정합니다.

속성 설명 기본값
AllowedUserNameCharacters 사용자 이름에 허용되는 문자입니다. abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
0123456789
-._@+
RequireUniqueEmail 각 사용자에게 고유한 이메일이 있어야 합니다. false

Program.cs에서 앱의 cookie를 구성합니다. ConfigureApplicationCookie는 호출 AddIdentity 후 호출해야 합니다.AddDefaultIdentity

builder.Services.ConfigureApplicationCookie(options =>
{
    options.AccessDeniedPath = "/Identity/Account/AccessDenied";
    options.Cookie.Name = "YourAppCookieName";
    options.Cookie.HttpOnly = true;
    options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
    options.LoginPath = "/Identity/Account/Login";
    // ReturnUrlParameter requires 
    //using Microsoft.AspNetCore.Authentication.Cookies;
    options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
    options.SlidingExpiration = true;
});

자세한 내용은 CookieAuthenticationOptions를 참조하세요.

암호 해서 옵션

PasswordHasherOptions는 암호 해시에 대한 옵션을 가져오고 설정합니다.

옵션 설명
CompatibilityMode 새 암호를 해시할 때 사용되는 호환성 모드입니다. 기본값은 IdentityV3입니다. 형식 표식이라고 하는 해시된 암호의 첫 번째 바이트는 암호를 해시하는 데 사용되는 해시 알고리즘의 버전을 지정합니다. 해시에 대해 암호를 확인할 때 VerifyHashedPassword 메서드는 첫 번째 바이트를 기반으로 올바른 알고리즘을 선택합니다. 클라이언트는 암호를 해시하는 데 사용된 알고리즘 버전에 관계없이 인증할 수 있습니다. 호환성 모드를 설정하면 새 암호의 해시에 영향을 미칩니다.
IterationCount PBKDF2를 사용하여 암호를 해시할 때 사용되는 반복 횟수입니다. 이 값은 CompatibilityModeIdentityV3으로 설정된 경우에만 사용됩니다. 값은 양의 정수여야 하며 기본값은 100000입니다.

다음 예제에서는 IterationCountProgram.cs에서 12000으로 설정됩니다.

// using Microsoft.AspNetCore.Identity;

builder.Services.Configure<PasswordHasherOptions>(option =>
{
    option.IterationCount = 12000;
});

전역적으로 모든 사용자를 인증하도록 요구

모든 사용자의 인증을 전역으로 요구하는 방법에 대한 자세한 내용은 인증된 사용자 요구를 참조하세요.

어디서나 ISecurityStampValidator 및 SignOut

앱은 사용자 ClaimsPrincipal을 다시 생성하여 보안에 중요한 작업과 관련된 이벤트에 대응해야 합니다. 예를 들어 역할을 조인하거나 암호를 변경하거나 기타 보안에 중요한 이벤트를 변경할 때 ClaimsPrincipal을 다시 생성해야 합니다. Identity는 ISecurityStampValidator 인터페이스를 사용하여 ClaimsPrincipal을 다시 생성합니다. Identity의 기본 구현은 SecurityStampValidator를 기본 애플리케이션 cookie 및 2단계 cookie와 함께 등록합니다. 유효성 검사기는 각 cookie의 OnValidatePrincipal 이벤트에 연결하여 Identity에 호출하고 사용자의 보안 스탬프 클레임이 cookie에 저장된 것과 달라지지 않았는지 확인합니다. 유효성 검사기는 정기적으로 호출합니다. 호출 간격은 데이터 저장소를 너무 자주 적중하는 것과 충분히 자주 적중하지 않는 것 사이의 절충입니다. 긴 간격으로 확인하면 부실 클레임이 발생합니다. 다음에 검사할 때 기존 쿠키가 무효화되도록 강제 호출 userManager.UpdateSecurityStampAsync(user)합니다. 대부분의 Identity UI 계정 및 관리 페이지는 암호를 변경하거나 로그인을 추가한 후 userManager.UpdateSecurityStampAsync(user)를 호출합니다. 앱은 userManager.UpdateSecurityStampAsync(user)를 호출하여 어디서나 로그아웃 작업을 구현할 수 있도록 합니다.

유효성 검사 간격 변경은 다음 강조 표시된 코드에 표시됩니다.

using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using WebClaimsPrincipal.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") 
    ?? throw new InvalidOperationException("'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => 
options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();

// Force Identity's security stamp to be validated every minute.
builder.Services.Configure<SecurityStampValidatorOptions>(o => 
                   o.ValidationInterval = TimeSpan.FromMinutes(1));

builder.Services.AddRazorPages();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

ASP.NET Core Identity는 암호 정책, 잠금 및 cookie 구성과 같은 설정에 기본값을 사용합니다. 이러한 설정은 Startup 클래스에서 재정의될 수 있습니다.

Identity 옵션

IdentityOptions 클래스는 Identity 시스템을 구성하는 데 사용할 수 있는 옵션을 나타냅니다. AddIdentity 또는 AddDefaultIdentity를 호출한 IdentityOptions를 설정해야 합니다.

클레임 Identity

IdentityOptions.ClaimsIdentity는 다음 표에 표시된 속성을 사용하여 ClaimsIdentityOptions를 지정합니다.

속성 설명 기본값
RoleClaimType 역할 클레임에 사용되는 클레임 형식을 가져오거나 설정합니다. ClaimTypes.Role
SecurityStampClaimType 보안 스탬프 클레임에 사용되는 클레임 형식을 가져오거나 설정합니다. AspNet.Identity.SecurityStamp
UserIdClaimType 사용자 식별자 클레임에 사용되는 클레임 형식을 가져오거나 설정합니다. ClaimTypes.NameIdentifier
UserNameClaimType 사용자 이름 클레임에 사용되는 클레임 형식을 가져오거나 설정합니다. ClaimTypes.Name

잠금

잠금은 PasswordSignInAsync 메서드에서 설정합니다.

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");

    if (ModelState.IsValid)
    {
        var result = await _signInManager.PasswordSignInAsync(Input.Email, 
            Input.Password, Input.RememberMe, 
            lockoutOnFailure: false);
        if (result.Succeeded)
        {
            _logger.LogInformation("User logged in.");
            return LocalRedirect(returnUrl);
        }
        if (result.RequiresTwoFactor)
        {
            return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl,
                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();
}

이전 코드는 LoginIdentity 템플릿을 기반으로 합니다.

잠금 옵션은 StartUp.ConfigureServices에서 설정됩니다.

services.Configure<IdentityOptions>(options =>
{
    // Default Lockout settings.
    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
    options.Lockout.MaxFailedAccessAttempts = 5;
    options.Lockout.AllowedForNewUsers = true;
});

앞의 코드는 기본값을 IdentityOptions LockoutOptions 설정합니다.

성공적인 인증은 실패한 액세스 시도 횟수를 다시 설정하고 시계를 다시 설정합니다.

IdentityOptions.Lockout 는 테이블에 표시된 속성을 사용하여 LockoutOptions를 지정합니다.

속성 설명 기본값
AllowedForNewUsers 새 사용자를 잠글 수 있는지 여부를 결정합니다. true
DefaultLockoutTimeSpan 잠금이 발생했을 때 사용자가 잠기는 시간입니다. 5분
MaxFailedAccessAttempts 잠금이 설정된 경우 사용자가 잠길 때까지 실패한 액세스 시도 횟수입니다. 5

암호

기본적으로 Identity에서는 암호에 대문자, 소문자, 숫자 및 영숫자가 아닌 문자를 포함해야 합니다. 암호 길이는 6자 이상이어야 합니다.

암호는 다음을 사용하여 구성됩니다.

  • Startup.ConfigureServicesPasswordOptions.
  • Identity가 앱에 스캐폴드된 경우 Password 속성의 [StringLength] 특성입니다. InputModelPassword 속성은 다음 파일에서 찾을 수 있습니다.
    • Areas/Identity/Pages/Account/Register.cshtml.cs
    • Areas/Identity/Pages/Account/ResetPassword.cshtml.cs
services.Configure<IdentityOptions>(options =>
{
    // Default 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;
});

IdentityOptions.Password 는 테이블에 표시된 속성을 사용하여 PasswordOptions를 지정합니다.

속성 설명 기본값
RequireDigit 암호에 0-9 사이의 숫자가 필요합니다. true
RequiredLength 암호의 최소 길이입니다. 6
RequireLowercase 암호에 소문자가 필요합니다. true
RequireNonAlphanumeric 암호에 영숫자가 아닌 문자가 필요합니다. true
RequiredUniqueChars ASP.NET Core 2.0 이상에만 적용됩니다.

암호에 고유한 문자 수가 필요합니다.
1
RequireUppercase 암호에 대문자가 필요합니다. true

로그인

다음 코드는 SignIn 설정을 기본값으로 설정합니다.

services.Configure<IdentityOptions>(options =>
{
    // Default SignIn settings.
    options.SignIn.RequireConfirmedEmail = false;
    options.SignIn.RequireConfirmedPhoneNumber = false;
});

IdentityOptions.SignIn 는 테이블에 표시된 속성을 사용하여 SignInOptions를 지정합니다.

속성 설명 기본값
RequireConfirmedEmail 로그인하려면 확인된 이메일이 필요합니다. false
RequireConfirmedPhoneNumber 로그인하려면 확인된 전화 번호가 필요합니다. false

토큰

IdentityOptions.Tokens 는 테이블에 표시된 속성을 사용하여 TokenOptions를 지정합니다.

속성 설명
AuthenticatorTokenProvider 인증자를 사용하여 2단계 로그인의 유효성을 검사하는 데 사용되는 AuthenticatorTokenProvider를 가져오거나 설정합니다.
ChangeEmailTokenProvider 이메일 변경 확인 이메일에 사용되는 토큰을 생성하는 데 사용되는 ChangeEmailTokenProvider를 가져오거나 설정합니다.
ChangePhoneNumberTokenProvider 전화 번호를 변경할 때 사용되는 토큰을 생성하는 데 사용되는 ChangePhoneNumberTokenProvider를 가져오거나 설정합니다.
EmailConfirmationTokenProvider 계정 확인 이메일에 사용되는 토큰을 생성하는 데 사용되는 토큰 공급자를 가져오거나 설정합니다.
PasswordResetTokenProvider 암호 재설정 전자 메일에 사용되는 토큰을 생성하는 데 사용되는 IUserTwoFactorTokenProvider<TUser>를 가져오거나 설정합니다.
ProviderMap 공급자 이름으로 사용되는 키를 사용하여 사용자 토큰 공급자를 구성하는 데 사용됩니다.

사용자

services.Configure<IdentityOptions>(options =>
{
    // Default User settings.
    options.User.AllowedUserNameCharacters =
            "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
    options.User.RequireUniqueEmail = false;

});

IdentityOptions.User 는 테이블에 표시된 속성을 사용하여 UserOptions를 지정합니다.

속성 설명 기본값
AllowedUserNameCharacters 사용자 이름에 허용되는 문자입니다. abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
0123456789
-._@+
RequireUniqueEmail 각 사용자에게 고유한 이메일이 있어야 합니다. false

Startup.ConfigureServices에서 앱의 cookie를 구성합니다. ConfigureApplicationCookie는 호출 AddIdentity 후 호출해야 합니다.AddDefaultIdentity

services.ConfigureApplicationCookie(options =>
{
    options.AccessDeniedPath = "/Identity/Account/AccessDenied";
    options.Cookie.Name = "YourAppCookieName";
    options.Cookie.HttpOnly = true;
    options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
    options.LoginPath = "/Identity/Account/Login";
    // ReturnUrlParameter requires 
    //using Microsoft.AspNetCore.Authentication.Cookies;
    options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
    options.SlidingExpiration = true;
});

자세한 내용은 CookieAuthenticationOptions를 참조하세요.

암호 해서 옵션

PasswordHasherOptions는 암호 해시에 대한 옵션을 가져오고 설정합니다.

옵션 설명
CompatibilityMode 새 암호를 해시할 때 사용되는 호환성 모드입니다. 기본값은 IdentityV3입니다. 형식 표식이라고 하는 해시된 암호의 첫 번째 바이트는 암호를 해시하는 데 사용되는 해시 알고리즘의 버전을 지정합니다. 해시에 대해 암호를 확인할 때 VerifyHashedPassword 메서드는 첫 번째 바이트를 기반으로 올바른 알고리즘을 선택합니다. 클라이언트는 암호를 해시하는 데 사용된 알고리즘 버전에 관계없이 인증할 수 있습니다. 호환성 모드를 설정하면 새 암호의 해시에 영향을 미칩니다.
IterationCount PBKDF2를 사용하여 암호를 해시할 때 사용되는 반복 횟수입니다. 이 값은 CompatibilityModeIdentityV3으로 설정된 경우에만 사용됩니다. 값은 양의 정수여야 하며 기본값은 10000입니다.

다음 예제에서는 IterationCountStartup.ConfigureServices에서 12000으로 설정됩니다.

// using Microsoft.AspNetCore.Identity;

services.Configure<PasswordHasherOptions>(option =>
{
    option.IterationCount = 12000;
});

전역적으로 모든 사용자를 인증하도록 요구

모든 사용자의 인증을 전역으로 요구하는 방법에 대한 자세한 내용은 인증된 사용자 요구를 참조하세요.