ASP.NET Core의 계정 확인 및 암호 복구
작성자: Rick Anderson, Ponant 및 Joe Audette
이 자습서에서는 이메일 확인 및 암호 재설정을 사용하여 ASP.NET Core 앱을 빌드하는 방법을 보여 줍니다. 이 자습서는 시작 항목이 아닙니다. 다음 사항을 잘 알고 있어야 합니다.
사전 요구 사항
인증을 사용하여 웹앱 만들기 및 테스트
다음 명령을 실행하여 인증을 사용하는 웹앱을 만듭니다.
dotnet new webapp -au Individual -o WebPWrecover
cd WebPWrecover
dotnet run
시뮬레이션된 전자 메일 확인을 사용하여 사용자 등록
앱을 실행하고 등록 링크를 선택한 후 사용자를 등록합니다. 등록되면 이메일 확인을 시뮬레이트하는 링크를 포함하는 /Identity/Account/RegisterConfirmation 페이지로 리디렉션됩니다.
Click here to confirm your account링크를 선택합니다.- 로그인 링크를 선택하고 동일한 자격 증명을 사용하여 로그인합니다.
- 페이지로
Hello YourEmail@provider.com!리디렉션/Identity/Account/Manage/PersonalData되는 링크를 선택합니다. - 왼쪽에서 개인 데이터 탭을 선택한 다음, 삭제를 선택합니다.
Click here to confirm your accountIEmailSender가 구현되지 않았고 디렉터리 삽입 컨테이너에 등록되지 않았기 때문에 링크가 표시됩니다. RegisterConfirmation 원본을 참조하세요.
이메일 공급자 구성
이 자습서에서는 SendGrid를 사용하여 이메일을 보냅니다. 전자 메일을 보내려면 SendGrid 계정 및 키가 필요합니다. 기타 전자 메일 공급자. SMTP 대신 SendGrid 또는 다른 전자 메일 서비스를 사용하여 전자 메일을 보내는 것이 좋습니다. SMTP는 안전하게 보호하고 올바르게 설정하기가 어렵습니다.
SendGrid 계정에는 보낸 사람을 추가해야 할 수 있습니다.
보안 이메일 키를 페치하는 클래스를 만듭니다. 이 샘플의 경우 다음을 만듭니다 Services/AuthMessageSenderOptions.cs.
namespace WebPWrecover.Services;
public class AuthMessageSenderOptions
{
public string? SendGridKey { get; set; }
}
SendGrid 사용자 비밀 구성
비밀 관리자 도구를 사용하여 SendGridKey를 설정합니다. 예를 들어:
dotnet user-secrets set SendGridKey <key>
Successfully saved SendGridKey to the secret store.
Windows에서 Secret Manager는 디렉터리의 파일에 키/값 쌍 secrets.json 을 %APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId> 저장합니다.
파일의 secrets.json 내용은 암호화되지 않습니다. 다음 태그는 파일을 보여 줍니다 secrets.json . SendGridKey 값이 제거되었습니다.
{
"SendGridKey": "<key removed>"
}
SendGrid 설치
이 자습서에서는 SendGrid를 통해 전자 메일 알림을 추가하는 방법을 보여 주지만 다른 전자 메일 공급자를 사용할 수 있습니다.
SendGrid NuGet 패키지를 설치합니다.
패키지 관리자 콘솔에서 다음 명령을 입력합니다.
Install-Package SendGrid
무료 SendGrid 계정에 등록하려면 무료 SendGrid 시작을 참조하세요.
IEmailSender 구현
구현 IEmailSender하려면 다음과 유사한 코드를 사용하여 만듭니 Services/EmailSender.cs 다.
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.Extensions.Options;
using SendGrid;
using SendGrid.Helpers.Mail;
namespace WebPWrecover.Services;
public class EmailSender : IEmailSender
{
private readonly ILogger _logger;
public EmailSender(IOptions<AuthMessageSenderOptions> optionsAccessor,
ILogger<EmailSender> logger)
{
Options = optionsAccessor.Value;
_logger = logger;
}
public AuthMessageSenderOptions Options { get; } //Set with Secret Manager.
public async Task SendEmailAsync(string toEmail, string subject, string message)
{
if (string.IsNullOrEmpty(Options.SendGridKey))
{
throw new Exception("Null SendGridKey");
}
await Execute(Options.SendGridKey, subject, message, toEmail);
}
public async Task Execute(string apiKey, string subject, string message, string toEmail)
{
var client = new SendGridClient(apiKey);
var msg = new SendGridMessage()
{
From = new EmailAddress("Joe@contoso.com", "Password Recovery"),
Subject = subject,
PlainTextContent = message,
HtmlContent = message
};
msg.AddTo(new EmailAddress(toEmail));
// Disable click tracking.
// See https://sendgrid.com/docs/User_Guide/Settings/tracking.html
msg.SetClickTracking(false, false);
var response = await client.SendEmailAsync(msg);
_logger.LogInformation(response.IsSuccessStatusCode
? $"Email to {toEmail} queued successfully!"
: $"Failure Email to {toEmail}");
}
}
전자 메일을 지원하도록 앱 구성
Program.cs 파일에 다음 코드를 추가합니다.
EmailSender를 임시 서비스로 추가합니다.AuthMessageSenderOptions구성 인스턴스를 등록합니다.
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.EntityFrameworkCore;
using WebPWrecover.Data;
using WebPWrecover.Services;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddTransient<IEmailSender, EmailSender>();
builder.Services.Configure<AuthMessageSenderOptions>(builder.Configuration);
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();
Account.RegisterConfirmation이 스캐폴드된 경우 기본 계정 확인 사용 안 함
이 섹션은 Account.RegisterConfirmation 스캐폴드된 경우에만 적용됩니다. 스캐폴드하지 않은 경우 이 섹션을 건너뜁니다 Account.RegisterConfirmation.
사용자는 계정을 확인하는 링크를 선택할 수 있는 위치로 리디렉션 Account.RegisterConfirmation 됩니다. 기본값 Account.RegisterConfirmation 은 테스트에 만 사용되며, 프로덕션 앱에서 자동 계정 확인을 사용하지 않도록 설정해야 합니다.
확인된 계정을 요구하고 등록 시 즉시 로그인을 방지하려면 스캐폴드된 /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs 파일에 설정합니다DisplayConfirmAccountLink = false.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using System;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.WebUtilities;
namespace WebPWrecover.Areas.Identity.Pages.Account
{
[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;
}
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public string Email { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public bool DisplayConfirmAccountLink { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public string EmailConfirmationUrl { get; set; }
public async Task<IActionResult> OnGetAsync(string email, string returnUrl = null)
{
if (email == null)
{
return RedirectToPage("/Index");
}
returnUrl = returnUrl ?? Url.Content("~/");
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();
}
}
}
이 단계는 스캐폴드된 경우에만 필요합니다 Account.RegisterConfirmation . 스캐폴드되지 않은 RegisterConfirmation 은 IEmailSender 가 구현되고 디렉터리 삽입 컨테이너 컨테이너 에 등록된 시기를 자동으로 검색합니다.
등록, 이메일 확인 및 암호 재설정
웹앱을 실행하고 계정 확인 및 암호 복구 흐름을 테스트합니다.
- 앱 실행 및 새 사용자 등록
- 계정 확인 링크에 사용할 이메일을 확인합니다. 이메일을 받지 못하면 이메일 디버그를 참조하세요.
- 링크를 클릭하여 이메일을 확인합니다.
- 이메일 및 암호를 사용하여 로그인합니다.
- 로그아웃합니다.
암호 재설정 테스트
- 로그인한 경우 로그아웃을 선택합니다.
- 로그인 링크를 선택하고 암호를 잊으셨나요? 링크를 선택합니다.
- 계정을 등록하는 데 사용한 이메일을 입력합니다.
- 암호를 재설정하는 링크가 포함된 이메일이 전송됩니다. 이메일을 확인하고 링크를 클릭하여 암호를 다시 설정합니다. 암호를 성공적으로 재설정한 후에는 이메일 및 새 암호로 로그인할 수 있습니다.
이메일 확인 다시 보내기
로그인 페이지에서 이메일 다시 보내기 확인 링크를 선택합니다.
이메일 및 작업 시간 제한 변경
기본 비활성 시간 제한은 14일입니다. 다음 코드는 비활성 시간 제한을 5일로 설정합니다.
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.EntityFrameworkCore;
using WebPWrecover.Data;
using WebPWrecover.Services;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddTransient<IEmailSender, EmailSender>();
builder.Services.Configure<AuthMessageSenderOptions>(builder.Configuration);
builder.Services.ConfigureApplicationCookie(o => {
o.ExpireTimeSpan = TimeSpan.FromDays(5);
o.SlidingExpiration = true;
});
var app = builder.Build();
// Code removed for brevity
모든 데이터 보호 토큰 수명 변경
다음 코드는 모든 데이터 보호 토큰 제한 시간을 3시간으로 변경합니다.
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.EntityFrameworkCore;
using WebPWrecover.Data;
using WebPWrecover.Services;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddTransient<IEmailSender, EmailSender>();
builder.Services.Configure<AuthMessageSenderOptions>(builder.Configuration);
builder.Services.Configure<DataProtectionTokenProviderOptions>(o =>
o.TokenLifespan = TimeSpan.FromHours(3));
var app = builder.Build();
// Code removed for brevity.
기본 제공 Identity 사용자 토큰(AspNetCore/src/Identity/Extensions.Core/src/TokenOptions.cs 참조)에는 1일 제한 시간이 있습니다.
이메일 토큰 수명 변경
Identity 사용자 토큰의 기본 토큰 수명은 1일입니다. 이 섹션에서는 이메일 토큰 수명을 변경하는 방법을 보여 줍니다.
사용자 지정을 DataProtectionTokenProviderOptions추가하고 다음을 수행합니다DataProtectorTokenProvider<TUser>.
public class CustomEmailConfirmationTokenProvider<TUser>
: DataProtectorTokenProvider<TUser> where TUser : class
{
public CustomEmailConfirmationTokenProvider(
IDataProtectionProvider dataProtectionProvider,
IOptions<EmailConfirmationTokenProviderOptions> options,
ILogger<DataProtectorTokenProvider<TUser>> logger)
: base(dataProtectionProvider, options, logger)
{
}
}
public class EmailConfirmationTokenProviderOptions : DataProtectionTokenProviderOptions
{
public EmailConfirmationTokenProviderOptions()
{
Name = "EmailDataProtectorTokenProvider";
TokenLifespan = TimeSpan.FromHours(4);
}
}
서비스 컨테이너에 사용자 지정 공급자를 추가합니다.
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.EntityFrameworkCore;
using WebPWrecover.Data;
using WebPWrecover.Services;
using WebPWrecover.TokenProviders;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(config =>
{
config.SignIn.RequireConfirmedEmail = true;
config.Tokens.ProviderMap.Add("CustomEmailConfirmation",
new TokenProviderDescriptor(
typeof(CustomEmailConfirmationTokenProvider<IdentityUser>)));
config.Tokens.EmailConfirmationTokenProvider = "CustomEmailConfirmation";
}).AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddTransient<CustomEmailConfirmationTokenProvider<IdentityUser>>();
builder.Services.AddRazorPages();
builder.Services.AddTransient<IEmailSender, EmailSender>();
builder.Services.Configure<AuthMessageSenderOptions>(builder.Configuration);
var app = builder.Build();
// Code removed for brevity.
이메일 디버그
이메일을 사용할 수 없는 경우:
EmailSender.Execute에서 중단점을 설정하여SendGridClient.SendEmailAsync가 호출되는지 확인합니다.EmailSender.Execute와 유사한 코드를 사용하여 이메일을 보내는 콘솔 앱을 만듭니다.- 이메일 활동 페이지를 검토합니다.
- 스팸 폴더를 확인합니다.
- 다른 이메일 공급자(Microsoft, Yahoo, Gmail 등)에서 다른 이메일 별칭을 사용해 보세요.
- 다른 이메일 계정으로 전송해 보세요.
보안 모범 사례는 테스트 및 개발에 프로덕션 비밀을 사용하지 않는 것입니다. Azure에 앱을 게시하는 경우 Azure 웹앱 포털에서 SendGrid 비밀을 애플리케이션 설정으로 설정합니다. 구성 시스템은 환경 변수에서 키를 읽도록 설정됩니다.
소셜 및 로컬 로그인 계정 결합
이 섹션을 완료하려면 먼저 외부 인증 공급자를 사용하도록 설정해야 합니다. Facebook, Google 및 외부 공급자 인증을 참조하세요.
이메일 링크를 클릭하여 로컬 및 소셜 계정을 결합할 수 있습니다. 다음 시퀀스에서는 “RickAndMSFT@gmail.com”이 로컬 로그인으로 먼저 생성되지만 계정을 소셜 로그인으로 먼저 만든 다음, 로컬 로그인을 추가할 수 있습니다.

관리 링크를 클릭합니다. 이 계정과 연결된 외부(소셜 로그인)가 0개임을 확인합니다.

다른 로그인 서비스에 대한 링크를 클릭하고 앱 요청을 수락합니다. 다음 이미지에서는 Facebook이 외부 인증 공급자입니다.

두 계정이 결합되었습니다. 두 계정 중 하나를 사용하여 로그인할 수 있습니다. 소셜 로그인 인증 서비스가 다운되거나 소셜 계정에 대한 액세스 권한이 손실된 경우 사용자가 로컬 계정을 추가하도록 할 수 있습니다.
사이트에 사용자가 있을 때 계정 확인 사용
사용자가 있는 사이트에서 계정 확인을 활성화하면 기존 사용자가 모두 잠깁니다. 기존 사용자는 계정이 확인되지 않으므로 잠겨 있습니다. 기존 사용자 잠금을 해결하려면 다음 방법 중 하나를 사용합니다.
- 모든 기존 사용자를 확인으로 표시하도록 데이터베이스를 업데이트합니다.
- 기존 사용자를 확인합니다. 예를 들어 확인 링크가 있는 이메일을 일괄 처리로 보냅니다.
사전 요구 사항
인증을 사용하여 웹앱 만들기 및 테스트
다음 명령을 실행하여 인증을 사용하는 웹앱을 만듭니다.
dotnet new webapp -au Individual -uld -o WebPWrecover
cd WebPWrecover
dotnet run
앱을 실행하고 등록 링크를 선택한 후 사용자를 등록합니다. 등록되면 이메일 확인을 시뮬레이트하는 링크를 포함하는 /Identity/Account/RegisterConfirmation 페이지로 리디렉션됩니다.
Click here to confirm your account링크를 선택합니다.- 로그인 링크를 선택하고 동일한 자격 증명을 사용하여 로그인합니다.
/Identity/Account/Manage/PersonalData페이지로 리디렉션되는Hello YourEmail@provider.com!링크를 선택합니다.- 왼쪽에서 개인 데이터 탭을 선택한 다음, 삭제를 선택합니다.
이메일 공급자 구성
이 자습서에서는 SendGrid를 사용하여 이메일을 보냅니다. 다른 이메일 공급자를 사용할 수 있습니다. SendGrid 또는 다른 이메일 서비스를 사용하여 이메일을 보내는 것이 좋습니다. SMTP는 구성하기 어렵기 때문에 메일이 스팸으로 표시되지 않습니다.
SendGrid 계정에는 보낸 사람을 추가해야 할 수 있습니다.
보안 이메일 키를 페치하는 클래스를 만듭니다. 이 샘플의 경우 다음을 만듭니다 Services/AuthMessageSenderOptions.cs.
namespace WebPWrecover.Services;
public class AuthMessageSenderOptions
{
public string? SendGridKey { get; set; }
}
SendGrid 사용자 비밀 구성
비밀 관리자 도구를 사용하여 SendGridKey를 설정합니다. 예를 들어:
dotnet user-secrets set SendGridKey <SG.key>
Successfully saved SendGridKey = SG.keyVal to the secret store.
Windows에서 Secret Manager는 디렉터리의 파일에 키/값 쌍 secrets.json 을 %APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId> 저장합니다.
파일의 secrets.json 내용은 암호화되지 않습니다. 다음 태그는 파일을 보여 줍니다 secrets.json . SendGridKey 값이 제거되었습니다.
{
"SendGridKey": "<key removed>"
}
SendGrid 설치
이 자습서에서는 SendGrid를 통해 이메일 알림을 추가하는 방법을 보여 주지만 SMTP 및 기타 메커니즘을 사용하여 이메일을 보낼 수 있습니다.
SendGrid NuGet 패키지를 설치합니다.
패키지 관리자 콘솔에서 다음 명령을 입력합니다.
Install-Package SendGrid
무료 SendGrid 계정에 등록하려면 무료 SendGrid 시작을 참조하세요.
IEmailSender 구현
구현 IEmailSender하려면 다음과 유사한 코드를 사용하여 만듭니 Services/EmailSender.cs 다.
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.Extensions.Options;
using SendGrid;
using SendGrid.Helpers.Mail;
namespace WebPWrecover.Services;
public class EmailSender : IEmailSender
{
private readonly ILogger _logger;
public EmailSender(IOptions<AuthMessageSenderOptions> optionsAccessor,
ILogger<EmailSender> logger)
{
Options = optionsAccessor.Value;
_logger = logger;
}
public AuthMessageSenderOptions Options { get; } //Set with Secret Manager.
public async Task SendEmailAsync(string toEmail, string subject, string message)
{
if (string.IsNullOrEmpty(Options.SendGridKey))
{
throw new Exception("Null SendGridKey");
}
await Execute(Options.SendGridKey, subject, message, toEmail);
}
public async Task Execute(string apiKey, string subject, string message, string toEmail)
{
var client = new SendGridClient(apiKey);
var msg = new SendGridMessage()
{
From = new EmailAddress("Joe@contoso.com", "Password Recovery"),
Subject = subject,
PlainTextContent = message,
HtmlContent = message
};
msg.AddTo(new EmailAddress(toEmail));
// Disable click tracking.
// See https://sendgrid.com/docs/User_Guide/Settings/tracking.html
msg.SetClickTracking(false, false);
var response = await client.SendEmailAsync(msg);
_logger.LogInformation(response.IsSuccessStatusCode
? $"Email to {toEmail} queued successfully!"
: $"Failure Email to {toEmail}");
}
}
이메일을 지원하도록 시작 구성
파일의 메서드 Startup.cs 에 ConfigureServices 다음 코드를 추가합니다.
EmailSender를 임시 서비스로 추가합니다.AuthMessageSenderOptions구성 인스턴스를 등록합니다.
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.EntityFrameworkCore;
using WebPWrecover.Data;
using WebPWrecover.Services;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddTransient<IEmailSender, EmailSender>();
builder.Services.Configure<AuthMessageSenderOptions>(builder.Configuration);
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();
RegisterConfirmation 스캐폴드
스캐폴드Identity 및 Account\RegisterConfirmation 스캐폴드에 대한 지침을 따릅니다.
Account.RegisterConfirmation이 스캐폴드된 경우 기본 계정 확인 사용 안 함
이 섹션은 Account.RegisterConfirmation 스캐폴드된 경우에만 적용됩니다. 스캐폴드하지 않은 경우 이 섹션을 건너뜁니다 Account.RegisterConfirmation.
사용자는 계정을 확인하는 링크를 선택할 수 있는 위치로 리디렉션 Account.RegisterConfirmation 됩니다. 기본값 Account.RegisterConfirmation 은 테스트에 만 사용되며, 프로덕션 앱에서 자동 계정 확인을 사용하지 않도록 설정해야 합니다.
확인된 계정을 요구하고 등록 시 즉시 로그인을 방지하려면 스캐폴드된 /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs 파일에 설정합니다DisplayConfirmAccountLink = false.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using System;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.WebUtilities;
namespace WebPWrecover.Areas.Identity.Pages.Account
{
[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;
}
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public string Email { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public bool DisplayConfirmAccountLink { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public string EmailConfirmationUrl { get; set; }
public async Task<IActionResult> OnGetAsync(string email, string returnUrl = null)
{
if (email == null)
{
return RedirectToPage("/Index");
}
returnUrl = returnUrl ?? Url.Content("~/");
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();
}
}
}
이 단계는 스캐폴드된 경우에만 필요합니다 Account.RegisterConfirmation . 스캐폴드되지 않은 RegisterConfirmation 은 IEmailSender 가 구현되고 디렉터리 삽입 컨테이너 컨테이너 에 등록된 시기를 자동으로 검색합니다.
등록, 이메일 확인 및 암호 재설정
웹앱을 실행하고 계정 확인 및 암호 복구 흐름을 테스트합니다.
- 앱 실행 및 새 사용자 등록
- 계정 확인 링크에 사용할 이메일을 확인합니다. 이메일을 받지 못하면 이메일 디버그를 참조하세요.
- 링크를 클릭하여 이메일을 확인합니다.
- 이메일 및 암호를 사용하여 로그인합니다.
- 로그아웃합니다.
암호 재설정 테스트
- 로그인한 경우 로그아웃을 선택합니다.
- 로그인 링크를 선택하고 암호를 잊으셨나요? 링크를 선택합니다.
- 계정을 등록하는 데 사용한 이메일을 입력합니다.
- 암호를 재설정하는 링크가 포함된 이메일이 전송됩니다. 이메일을 확인하고 링크를 클릭하여 암호를 다시 설정합니다. 암호를 성공적으로 재설정한 후에는 이메일 및 새 암호로 로그인할 수 있습니다.
이메일 확인 다시 보내기
ASP.NET Core 5.0 이상에서는 로그인 페이지에서 이메일 확인 다시 보내기 링크를 선택합니다.
이메일 및 작업 시간 제한 변경
기본 비활성 시간 제한은 14일입니다. 다음 코드는 비활성 시간 제한을 5일로 설정합니다.
services.ConfigureApplicationCookie(o => {
o.ExpireTimeSpan = TimeSpan.FromDays(5);
o.SlidingExpiration = true;
});
모든 데이터 보호 토큰 수명 변경
다음 코드는 모든 데이터 보호 토큰 제한 시간을 3시간으로 변경합니다.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(
options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.Configure<DataProtectionTokenProviderOptions>(o =>
o.TokenLifespan = TimeSpan.FromHours(3));
services.AddTransient<IEmailSender, EmailSender>();
services.Configure<AuthMessageSenderOptions>(Configuration);
services.AddRazorPages();
}
기본 제공 Identity 사용자 토큰(AspNetCore/src/Identity/Extensions.Core/src/TokenOptions.cs 참조)에는 1일 제한 시간이 있습니다.
이메일 토큰 수명 변경
Identity 사용자 토큰의 기본 토큰 수명은 1일입니다. 이 섹션에서는 이메일 토큰 수명을 변경하는 방법을 보여 줍니다.
사용자 지정을 DataProtectionTokenProviderOptions추가하고 다음을 수행합니다DataProtectorTokenProvider<TUser>.
public class CustomEmailConfirmationTokenProvider<TUser>
: DataProtectorTokenProvider<TUser> where TUser : class
{
public CustomEmailConfirmationTokenProvider(IDataProtectionProvider dataProtectionProvider,
IOptions<EmailConfirmationTokenProviderOptions> options,
ILogger<DataProtectorTokenProvider<TUser>> logger)
: base(dataProtectionProvider, options, logger)
{
}
}
public class EmailConfirmationTokenProviderOptions : DataProtectionTokenProviderOptions
{
public EmailConfirmationTokenProviderOptions()
{
Name = "EmailDataProtectorTokenProvider";
TokenLifespan = TimeSpan.FromHours(4);
}
}
서비스 컨테이너에 사용자 지정 공급자를 추가합니다.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(config =>
{
config.SignIn.RequireConfirmedEmail = true;
config.Tokens.ProviderMap.Add("CustomEmailConfirmation",
new TokenProviderDescriptor(
typeof(CustomEmailConfirmationTokenProvider<IdentityUser>)));
config.Tokens.EmailConfirmationTokenProvider = "CustomEmailConfirmation";
}).AddEntityFrameworkStores<ApplicationDbContext>();
services.AddTransient<CustomEmailConfirmationTokenProvider<IdentityUser>>();
services.AddTransient<IEmailSender, EmailSender>();
services.Configure<AuthMessageSenderOptions>(Configuration);
services.AddRazorPages();
}
이메일 디버그
이메일을 사용할 수 없는 경우:
EmailSender.Execute에서 중단점을 설정하여SendGridClient.SendEmailAsync가 호출되는지 확인합니다.EmailSender.Execute와 유사한 코드를 사용하여 이메일을 보내는 콘솔 앱을 만듭니다.- 이메일 활동 페이지를 검토합니다.
- 스팸 폴더를 확인합니다.
- 다른 이메일 공급자(Microsoft, Yahoo, Gmail 등)에서 다른 이메일 별칭을 사용해 보세요.
- 다른 이메일 계정으로 전송해 보세요.
보안 모범 사례는 테스트 및 개발에 프로덕션 비밀을 사용하지 않는 것입니다. Azure에 앱을 게시하는 경우 Azure 웹앱 포털에서 SendGrid 비밀을 애플리케이션 설정으로 설정합니다. 구성 시스템은 환경 변수에서 키를 읽도록 설정됩니다.
소셜 및 로컬 로그인 계정 결합
이 섹션을 완료하려면 먼저 외부 인증 공급자를 사용하도록 설정해야 합니다. Facebook, Google 및 외부 공급자 인증을 참조하세요.
이메일 링크를 클릭하여 로컬 및 소셜 계정을 결합할 수 있습니다. 다음 시퀀스에서는 “RickAndMSFT@gmail.com”이 로컬 로그인으로 먼저 생성되지만 계정을 소셜 로그인으로 먼저 만든 다음, 로컬 로그인을 추가할 수 있습니다.

관리 링크를 클릭합니다. 이 계정과 연결된 외부(소셜 로그인)가 0개임을 확인합니다.

다른 로그인 서비스에 대한 링크를 클릭하고 앱 요청을 수락합니다. 다음 이미지에서는 Facebook이 외부 인증 공급자입니다.

두 계정이 결합되었습니다. 두 계정 중 하나를 사용하여 로그인할 수 있습니다. 소셜 로그인 인증 서비스가 다운되거나 소셜 계정에 대한 액세스 권한이 손실된 경우 사용자가 로컬 계정을 추가하도록 할 수 있습니다.
사이트에 사용자가 있을 때 계정 확인 사용
사용자가 있는 사이트에서 계정 확인을 활성화하면 기존 사용자가 모두 잠깁니다. 기존 사용자는 계정이 확인되지 않으므로 잠겨 있습니다. 기존 사용자 잠금을 해결하려면 다음 방법 중 하나를 사용합니다.
- 모든 기존 사용자를 확인으로 표시하도록 데이터베이스를 업데이트합니다.
- 기존 사용자를 확인합니다. 예를 들어 확인 링크가 있는 이메일을 일괄 처리로 보냅니다.