ASP.NET Core의 계정 확인 및 암호 복구Account confirmation and password recovery in ASP.NET Core

Rick Anderson, PonantJoe AudetteBy Rick Anderson, Ponant, and Joe Audette

이 자습서에서는 전자 메일 확인 및 암호 재설정을 사용 하 여 ASP.NET Core 앱을 빌드하는 방법을 보여 줍니다.This tutorial shows how to build an ASP.NET Core app with email confirmation and password reset. 이 자습서는 시작 항목이 아닙니다 .This tutorial is not a beginning topic. 다음에 대해 잘 알고 있어야 합니다.You should be familiar with:

필수 구성 요소Prerequisites

.NET Core 3.0 SDK 이상.NET Core 3.0 SDK or later

인증을 사용 하 여 웹 앱 만들기 및 테스트Create and test a web app with authentication

다음 명령을 실행 하 여 인증을 사용 하는 웹 앱을 만듭니다.Run the following commands to create a web app with authentication.

dotnet new webapp -au Individual -uld -o WebPWrecover
cd WebPWrecover
dotnet run

앱을 실행 하 고, 등록 링크를 선택 하 고, 사용자를 등록 합니다.Run the app, select the Register link, and register a user. 등록 되 면 /Identity/Account/RegisterConfirmation 전자 메일 확인을 시뮬레이트하는 링크를 포함 하는 to 페이지로 리디렉션됩니다.Once registered, you are redirected to the to /Identity/Account/RegisterConfirmation page which contains a link to simulate email confirmation:

  • Click here to confirm your account 링크를 선택합니다.Select the Click here to confirm your account link.
  • 로그인 링크를 선택 하 고 동일한 자격 증명을 사용 하 여 로그인 합니다.Select the Login link and sign-in with the same credentials.
  • Hello YourEmail@provider.com!페이지로 리디렉션되는 링크를 선택 합니다 /Identity/Account/Manage/PersonalData .Select the Hello YourEmail@provider.com! link, which redirects you to the /Identity/Account/Manage/PersonalData page.
  • 왼쪽에서 개인 데이터 탭을 선택 하 고 삭제를 선택 합니다.Select the Personal data tab on the left, and then select Delete.

전자 메일 공급자 구성Configure an email provider

이 자습서에서는 SendGrid 를 사용 하 여 전자 메일을 보냅니다.In this tutorial, SendGrid is used to send email. 전자 메일을 보내려면 SendGrid 계정 및 키가 필요 합니다.You need a SendGrid account and key to send email. 다른 전자 메일 공급자를 사용할 수 있습니다.You can use other email providers. SendGrid 또는 다른 전자 메일 서비스를 사용 하 여 전자 메일을 보내는 것이 좋습니다.We recommend you use SendGrid or another email service to send email. SMTP는 안전 하 게 보호 하 고 올바르게 설정 하기 어렵습니다.SMTP is difficult to secure and set up correctly.

SendGrid 계정에는 발신자를 추가해야 할 수 있습니다.The SendGrid account may require adding a Sender.

보안 전자 메일 키를 인출 하는 클래스를 만듭니다.Create a class to fetch the secure email key. 이 샘플의 경우 Services/AuthMessageSenderOptions을 만듭니다.For this sample, create Services/AuthMessageSenderOptions.cs:

public class AuthMessageSenderOptions
{
    public string SendGridUser { get; set; }
    public string SendGridKey { get; set; }
}

SendGrid 사용자 비밀 구성Configure SendGrid user secrets

SendGridUser SendGridKey 암호 관리자 도구를 사용 하 여 및를 설정 합니다.Set the SendGridUser and SendGridKey with the secret-manager tool. 예를 들면For example:

dotnet user-secrets set SendGridUser RickAndMSFT
dotnet user-secrets set SendGridKey <key>

Successfully saved SendGridUser = RickAndMSFT to the secret store.

Windows에서 Secret Manager는 디렉터리의 파일 * 에 있는secrets.js* 의 키/값 쌍을 저장 %APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId> 합니다.On Windows, Secret Manager stores keys/value pairs in a secrets.json file in the %APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId> directory.

파일의 secrets.js 내용이 암호화 되지 않았습니다.The contents of the secrets.json file aren't encrypted. 다음 태그는 파일 * 의secrets.js* 을 보여 줍니다.The following markup shows the secrets.json file. SendGridKey값이 제거 되었습니다.The SendGridKey value has been removed.

{
  "SendGridUser": "RickAndMSFT",
  "SendGridKey": "<key removed>"
}

자세한 내용은 옵션 패턴구성을 참조 하세요.For more information, see the Options pattern and configuration.

SendGrid 설치Install SendGrid

이 자습서에서는 SendGrid를 통해 전자 메일 알림을 추가 하는 방법을 보여 주지만 SMTP 및 기타 메커니즘을 사용 하 여 전자 메일을 보낼 수 있습니다.This tutorial shows how to add email notifications through SendGrid, but you can send email using SMTP and other mechanisms.

NuGet 패키지를 설치 합니다 SendGrid .Install the SendGrid NuGet package:

패키지 관리자 콘솔에서 다음 명령을 입력 합니다.From the Package Manager Console, enter the following command:

Install-Package SendGrid

무료 SendGrid 계정에 등록 하려면 무료로 SendGrid 시작 을 참조 하세요.See Get Started with SendGrid for Free to register for a free SendGrid account.

IEmailSender 구현Implement IEmailSender

를 구현 하려면 IEmailSender 다음과 유사한 코드를 사용 하 여 서비스/emailsender .cs 를 만듭니다.To Implement IEmailSender, create Services/EmailSender.cs with code similar to the following:

using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.Extensions.Options;
using SendGrid;
using SendGrid.Helpers.Mail;
using System.Threading.Tasks;

namespace WebPWrecover.Services
{
    public class EmailSender : IEmailSender
    {
        public EmailSender(IOptions<AuthMessageSenderOptions> optionsAccessor)
        {
            Options = optionsAccessor.Value;
        }

        public AuthMessageSenderOptions Options { get; } //set only via Secret Manager

        public Task SendEmailAsync(string email, string subject, string message)
        {
            return Execute(Options.SendGridKey, subject, message, email);
        }

        public Task Execute(string apiKey, string subject, string message, string email)
        {
            var client = new SendGridClient(apiKey);
            var msg = new SendGridMessage()
            {
                From = new EmailAddress("Joe@contoso.com", Options.SendGridUser),
                Subject = subject,
                PlainTextContent = message,
                HtmlContent = message
            };
            msg.AddTo(new EmailAddress(email));

            // Disable click tracking.
            // See https://sendgrid.com/docs/User_Guide/Settings/tracking.html
            msg.SetClickTracking(false, false);

            return client.SendEmailAsync(msg);
        }
    }
}

전자 메일을 지원 하도록 시작 구성Configure startup to support email

ConfigureServices Startup.cs 파일의 메서드에 다음 코드를 추가 합니다.Add the following code to the ConfigureServices method in the Startup.cs file:

  • EmailSender 임시 서비스로 추가 합니다.Add EmailSender as a transient service.
  • AuthMessageSenderOptions구성 인스턴스를 등록 합니다.Register the AuthMessageSenderOptions configuration instance.
public void ConfigureServices(IServiceCollection services)
{

    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));
    services.AddDefaultIdentity<IdentityUser>(
                  options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();

    // requires
    // using Microsoft.AspNetCore.Identity.UI.Services;
    // using WebPWrecover.Services;
    services.AddTransient<IEmailSender, EmailSender>();
    services.Configure<AuthMessageSenderOptions>(Configuration);

    services.AddRazorPages();
}

스 캐 폴드 RegisterConfirmationScaffold RegisterConfirmation

스 캐 폴드 Identity 및 스 캐 폴드에 대 한 지침을 따릅니다 RegisterConfirmation .Follow the instructions for Scaffold Identity and scaffold RegisterConfirmation.

기본 계정 확인 사용 안 함Disable default account verification

기본 템플릿을 사용 하면 사용자가 Account.RegisterConfirmation 계정 확인을 위해 링크를 선택할 수 있는 위치로 리디렉션됩니다.With the default templates, the user is redirected to the Account.RegisterConfirmation where they can select a link to have the account confirmed. 기본값은 Account.RegisterConfirmation 테스트에 사용 되며 자동 계정 확인은 프로덕션 앱에서 사용 하지 않도록 설정 해야 합니다.The default Account.RegisterConfirmation is used only for testing, automatic account verification should be disabled in a production app.

확인 된 계정을 요구 하 고 등록 시 즉시 로그인을 방지 하려면 DisplayConfirmAccountLink = false /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs에서를 설정 합니다.To require a confirmed account and prevent immediate login at registration, set DisplayConfirmAccountLink = false in /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();
    }
}

등록, 전자 메일 확인 및 암호 재설정Register, confirm email, and reset password

웹 앱을 실행 하 고 계정 확인 및 암호 복구 흐름을 테스트 합니다.Run the web app, and test the account confirmation and password recovery flow.

  • 앱을 실행 하 고 새 사용자를 등록 합니다.Run the app and register a new user
  • 계정 확인 링크에 대 한 전자 메일을 확인 합니다.Check your email for the account confirmation link. 전자 메일을 받을 수 없는 경우 디버그 전자 메일 을 참조 하세요.See Debug email if you don't get the email.
  • 링크를 클릭 하 여 전자 메일을 확인 합니다.Click the link to confirm your email.
  • 전자 메일 및 암호를 사용 하 여 로그인 합니다.Sign in with your email and password.
  • 로그아웃합니다.Sign out.

암호 재설정 테스트Test password reset

  • 로그인 하는 경우 로그 아웃을 선택 합니다.If you're signed in, select Logout.
  • 로그인 링크를 선택 하 고 암호를 잊으셨나요? 링크를 선택 합니다.Select the Log in link and select the Forgot your password? link.
  • 계정을 등록 하는 데 사용한 전자 메일을 입력 합니다.Enter the email you used to register the account.
  • 암호를 재설정 하는 링크가 포함 된 전자 메일이 전송 됩니다.An email with a link to reset your password is sent. 전자 메일을 확인 하 고 링크를 클릭 하 여 암호를 다시 설정 합니다.Check your email and click the link to reset your password. 암호를 성공적으로 재설정 한 후에는 전자 메일 및 새 암호로 로그인 할 수 있습니다.After your password has been successfully reset, you can sign in with your email and new password.

전자 메일 다시 보내기 확인Resend email confirmation

ASP.NET Core 5.0 이상에서는 로그인 페이지에서 전자 메일 다시 보내기 확인 링크를 선택 합니다.In ASP.NET Core 5.0 and later, select the Resend email confirmation link on the Login page.

전자 메일 및 작업 시간 제한 변경Change email and activity timeout

기본 비활성 시간 제한은 14 일입니다.The default inactivity timeout is 14 days. 다음 코드는 비활성 시간 제한을 5 일로 설정 합니다.The following code sets the inactivity timeout to 5 days:

services.ConfigureApplicationCookie(o => {
    o.ExpireTimeSpan = TimeSpan.FromDays(5);
    o.SlidingExpiration = true;
});

모든 데이터 보호 토큰 변경 lifespansChange all data protection token lifespans

다음 코드는 모든 데이터 보호 토큰 제한 시간을 3 시간으로 변경 합니다.The following code changes all data protection tokens timeout period to 3 hours:

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 일 시간 제한이있습니다.The built in Identity user tokens (see AspNetCore/src/Identity/Extensions.Core/src/TokenOptions.cs )have a one day timeout.

전자 메일 토큰 수명 변경Change the email token lifespan

Identity 사용자 토큰 의 기본 토큰 수명은 1 일입니다.The default token lifespan of the Identity user tokens is one day. 이 섹션에서는 전자 메일 토큰 수명을 변경 하는 방법을 보여 줍니다.This section shows how to change the email token lifespan.

사용자 지정 DataProtectorTokenProvider <TUser> 및를 추가 합니다 DataProtectionTokenProviderOptions .Add a custom DataProtectorTokenProvider<TUser> and DataProtectionTokenProviderOptions:

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);
    }
}

서비스 컨테이너에 사용자 지정 공급자를 추가 합니다.Add the custom provider to the service container:

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

디버그 전자 메일Debug email

전자 메일을 사용할 수 없는 경우:If you can't get email working:

  • EmailSender.Execute가 호출 되었는지 확인 하려면에서 중단점을 설정 SendGridClient.SendEmailAsync 합니다.Set a breakpoint in EmailSender.Execute to verify SendGridClient.SendEmailAsync is called.
  • 비슷한 코드를 사용 하 여 전자 메일을 보내는 콘솔 앱 을 만듭니다 EmailSender.Execute .Create a console app to send email using similar code to EmailSender.Execute.
  • 전자 메일 작업 페이지를 검토 합니다.Review the Email Activity page.
  • 스팸 폴더를 확인 합니다.Check your spam folder.
  • 다른 전자 메일 공급자 (Microsoft, Yahoo, Gmail 등)에서 다른 전자 메일 별칭을 사용해 보세요.Try another email alias on a different email provider (Microsoft, Yahoo, Gmail, etc.)
  • 다른 전자 메일 계정으로 전송 해 보세요.Try sending to different email accounts.

보안 모범 사례 는 테스트 및 개발에서 프로덕션 암호를 사용 하지 않는 것입니다.A security best practice is to not use production secrets in test and development. Azure에 앱을 게시 하는 경우 Azure 웹 앱 포털에서 SendGrid 비밀을 응용 프로그램 설정으로 설정 합니다.If you publish the app to Azure, set the SendGrid secrets as application settings in the Azure Web App portal. 구성 시스템은 환경 변수에서 키를 읽도록 설정 되어 있습니다.The configuration system is set up to read keys from environment variables.

소셜 및 로컬 로그인 계정 결합Combine social and local login accounts

이 섹션을 완료 하려면 먼저 외부 인증 공급자를 사용 하도록 설정 해야 합니다.To complete this section, you must first enable an external authentication provider. Facebook, Google 및 외부 공급자 인증을 참조 하세요.See Facebook, Google, and external provider authentication.

전자 메일 링크를 클릭 하 여 로컬 및 소셜 계정을 결합할 수 있습니다.You can combine local and social accounts by clicking on your email link. 다음 시퀀스에서는 " RickAndMSFT@gmail.com "이 (가) 로컬 로그인으로 먼저 생성 되지만 계정을 소셜 로그인으로 먼저 만든 다음 로컬 로그인을 추가할 수 있습니다.In the following sequence, "RickAndMSFT@gmail.com" is first created as a local login; however, you can create the account as a social login first, then add a local login.

웹 응용 프로그램: RickAndMSFT@gmail.com 사용자 인증 됨

관리 링크를 클릭 합니다.Click on the Manage link. 이 계정과 연결 된 0 외부 (소셜 로그인)를 확인 합니다.Note the 0 external (social logins) associated with this account.

뷰 관리

다른 로그인 서비스에 대 한 링크를 클릭 하 고 앱 요청을 수락 합니다.Click the link to another login service and accept the app requests. 다음 이미지에서 Facebook은 외부 인증 공급자입니다.In the following image, Facebook is the external authentication provider:

외부 로그인 보기 관리 Facebook 목록

두 계정을 결합 했습니다.The two accounts have been combined. 두 계정을 사용 하 여 로그인 할 수 있습니다.You are able to sign in with either account. 소셜 로그인 인증 서비스가 다운 되거나 소셜 계정에 대 한 액세스 권한이 손실 될 가능성이 있는 경우 사용자가 로컬 계정을 추가 하도록 할 수 있습니다.You might want your users to add local accounts in case their social login authentication service is down, or more likely they've lost access to their social account.

사이트에 사용자가 있는 후 계정 확인 사용Enable account confirmation after a site has users

사용자가 있는 사이트에서 계정 확인을 사용 하도록 설정 하면 모든 기존 사용자가 잠깁니다.Enabling account confirmation on a site with users locks out all the existing users. 계정이 확인 되지 않았기 때문에 기존 사용자가 잠깁니다.Existing users are locked out because their accounts aren't confirmed. 기존 사용자 잠금을 해결 하려면 다음 방법 중 하나를 사용 합니다.To work around existing user lockout, use one of the following approaches:

  • 기존 사용자를 모두 확인 된 것으로 표시 하도록 데이터베이스를 업데이트 합니다.Update the database to mark all existing users as being confirmed.
  • 기존 사용자를 확인 합니다.Confirm existing users. 예를 들어, 확인 링크가 포함 된 메일을 일괄 보냅니다.For example, batch-send emails with confirmation links.

필수 구성 요소Prerequisites

.NET Core 2.2 SDK 이상.NET Core 2.2 SDK or later

웹 앱 및 스 캐 폴드 만들기 IdentityCreate a web app and scaffold Identity

다음 명령을 실행 하 여 인증을 사용 하는 웹 앱을 만듭니다.Run the following commands to create a web app with authentication.

dotnet new webapp -au Individual -uld -o WebPWrecover
cd WebPWrecover
dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
dotnet tool install -g dotnet-aspnet-codegenerator
dotnet aspnet-codegenerator identity -dc WebPWrecover.Data.ApplicationDbContext --files "Account.Register;Account.Login;Account.Logout;Account.ConfirmEmail"
dotnet ef database drop -f
dotnet ef database update
dotnet run

참고

PasswordOptions이에서 구성 된 경우 Startup.ConfigureServices 스 캐 폴드 pages의 속성에 대 한 [StringLength] 특성 구성이 필요할 수 있습니다 Password Identity .If PasswordOptions are configured in Startup.ConfigureServices, [StringLength] attribute configuration might be required for the Password property in scaffolded Identity pages. InputModel Password 속성은 Areas/Identity/Pages/Account/Register.cshtml.cs 스 캐 폴딩 후 파일에 있습니다 Identity .An InputModel Password property is found in the Areas/Identity/Pages/Account/Register.cshtml.cs file after scaffolding Identity.

새 사용자 등록 테스트Test new user registration

앱을 실행 하 고, 등록 링크를 선택 하 고, 사용자를 등록 합니다.Run the app, select the Register link, and register a user. 이때 전자 메일에 대 한 유일한 유효성 검사는 특성을 사용 [EmailAddress] 합니다.At this point, the only validation on the email is with the [EmailAddress] attribute. 등록을 제출 하면 앱에 로그인 됩니다.After submitting the registration, you are logged into the app. 자습서의 뒷부분에서 새로운 사용자가 전자 메일의 유효성을 검사할 때까지 로그인 할 수 없도록 코드를 업데이트 합니다.Later in the tutorial, the code is updated so new users can't sign in until their email is validated.

Identity 데이터베이스 보기View the Identity database

  • 보기 메뉴에서 SQL Server 개체 탐색기 (SSOX)를 선택 합니다.From the View menu, select SQL Server Object Explorer (SSOX).
  • (Localdb) MSSQLLocalDB (SQL Server 13) 로 이동 합니다.Navigate to (localdb)MSSQLLocalDB(SQL Server 13). Dbo를 마우스 오른쪽 단추로 클릭 합니다. AspNetUsers > 뷰 데이터:Right-click on dbo.AspNetUsers > View Data:

SQL Server 개체 탐색기에서 AspNetUsers 테이블에 대한 컨텍스트 메뉴

테이블의 필드는 EmailConfirmed False 입니다.Note the table's EmailConfirmed field is False.

앱에서 확인 전자 메일을 보낼 때 다음 단계에서이 전자 메일을 다시 사용 하는 것이 좋습니다.You might want to use this email again in the next step when the app sends a confirmation email. 행을 마우스 오른쪽 단추로 클릭 하 고 삭제를 선택 합니다.Right-click on the row and select Delete. 전자 메일 별칭을 삭제 하면 다음 단계에서 보다 쉽게 수행할 수 있습니다.Deleting the email alias makes it easier in the following steps.

전자 메일 확인 필요Require email confirmation

새 사용자 등록의 전자 메일을 확인 하는 것이 가장 좋습니다.It's a best practice to confirm the email of a new user registration. 전자 메일 확인을 사용 하면 다른 사용자를 가장 하지 않는 것을 확인할 수 있습니다. 즉, 다른 사용자의 전자 메일을 사용 하 여 등록 하지 않았습니다.Email confirmation helps to verify they're not impersonating someone else (that is, they haven't registered with someone else's email). 토론 포럼이 있고 ""을 ""로 등록 하지 못하도록 하는 경우를 가정해 보겠습니다 yli@example.com nolivetto@contoso.com .Suppose you had a discussion forum, and you wanted to prevent "yli@example.com" from registering as "nolivetto@contoso.com". 전자 메일 확인이 없으면 ""이 (가) nolivetto@contoso.com 앱에서 원치 않는 전자 메일을 받을 수 있습니다.Without email confirmation, "nolivetto@contoso.com" could receive unwanted email from your app. ""로 실수로 등록 한 사용자가 ylo@example.com "yli"의 맞춤법 오류를 발견 했다고 가정 합니다.Suppose the user accidentally registered as "ylo@example.com" and hadn't noticed the misspelling of "yli". 앱에 올바른 전자 메일이 없기 때문에 암호 복구를 사용할 수 없습니다.They wouldn't be able to use password recovery because the app doesn't have their correct email. 전자 메일 확인은 봇에서 제한 된 보호 기능을 제공 합니다.Email confirmation provides limited protection from bots. 전자 메일 확인은 전자 메일 계정이 많은 악의적인 사용자 로부터 보호를 제공 하지 않습니다.Email confirmation doesn't provide protection from malicious users with many email accounts.

일반적으로 새 사용자가 확인 된 전자 메일을 보내기 전에 데이터를 웹 사이트에 게시 하는 것을 방지 하려고 합니다.You generally want to prevent new users from posting any data to your web site before they have a confirmed email.

Startup.ConfigureServices확인 된 전자 메일을 요구 하도록 업데이트 합니다.Update Startup.ConfigureServices to require a confirmed email:

public void ConfigureServices(IServiceCollection services)
{

    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));

    services.AddDefaultIdentity<IdentityUser>(config =>
    {
        config.SignIn.RequireConfirmedEmail = true;
    })
        .AddDefaultUI(UIFramework.Bootstrap4)
        .AddEntityFrameworkStores<ApplicationDbContext>();

    // requires
    // using Microsoft.AspNetCore.Identity.UI.Services;
    // using WebPWrecover.Services;
    services.AddTransient<IEmailSender, EmailSender>();
    services.Configure<AuthMessageSenderOptions>(Configuration);

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

config.SignIn.RequireConfirmedEmail = true; 등록 된 사용자가 전자 메일을 확인할 때까지 로그인 하지 못하도록 합니다.config.SignIn.RequireConfirmedEmail = true; prevents registered users from logging in until their email is confirmed.

전자 메일 공급자 구성Configure email provider

이 자습서에서는 SendGrid 를 사용 하 여 전자 메일을 보냅니다.In this tutorial, SendGrid is used to send email. 전자 메일을 보내려면 SendGrid 계정 및 키가 필요 합니다.You need a SendGrid account and key to send email. 다른 전자 메일 공급자를 사용할 수 있습니다.You can use other email providers. ASP.NET Core 2.x에는 System.Net.Mail 앱에서 전자 메일을 보낼 수 있는가 포함 되어 있습니다.ASP.NET Core 2.x includes System.Net.Mail, which allows you to send email from your app. SendGrid 또는 다른 전자 메일 서비스를 사용 하 여 전자 메일을 보내는 것이 좋습니다.We recommend you use SendGrid or another email service to send email. SMTP는 안전 하 게 보호 하 고 올바르게 설정 하기 어렵습니다.SMTP is difficult to secure and set up correctly.

보안 전자 메일 키를 인출 하는 클래스를 만듭니다.Create a class to fetch the secure email key. 이 샘플의 경우 Services/AuthMessageSenderOptions을 만듭니다.For this sample, create Services/AuthMessageSenderOptions.cs:

public class AuthMessageSenderOptions
{
    public string SendGridUser { get; set; }
    public string SendGridKey { get; set; }
}

SendGrid 사용자 비밀 구성Configure SendGrid user secrets

SendGridUser SendGridKey 암호 관리자 도구를 사용 하 여 및를 설정 합니다.Set the SendGridUser and SendGridKey with the secret-manager tool. 예를 들면For example:

C:/WebAppl>dotnet user-secrets set SendGridUser RickAndMSFT
info: Successfully saved SendGridUser = RickAndMSFT to the secret store.

Windows에서 Secret Manager는 디렉터리의 파일 * 에 있는secrets.js* 의 키/값 쌍을 저장 %APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId> 합니다.On Windows, Secret Manager stores keys/value pairs in a secrets.json file in the %APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId> directory.

파일의 secrets.js 내용이 암호화 되지 않았습니다.The contents of the secrets.json file aren't encrypted. 다음 태그는 파일 * 의secrets.js* 을 보여 줍니다.The following markup shows the secrets.json file. SendGridKey값이 제거 되었습니다.The SendGridKey value has been removed.

{
  "SendGridUser": "RickAndMSFT",
  "SendGridKey": "<key removed>"
}

자세한 내용은 옵션 패턴구성을 참조 하세요.For more information, see the Options pattern and configuration.

SendGrid 설치Install SendGrid

이 자습서에서는 SendGrid를 통해 전자 메일 알림을 추가 하는 방법을 보여 주지만 SMTP 및 기타 메커니즘을 사용 하 여 전자 메일을 보낼 수 있습니다.This tutorial shows how to add email notifications through SendGrid, but you can send email using SMTP and other mechanisms.

NuGet 패키지를 설치 합니다 SendGrid .Install the SendGrid NuGet package:

패키지 관리자 콘솔에서 다음 명령을 입력 합니다.From the Package Manager Console, enter the following command:

Install-Package SendGrid

무료 SendGrid 계정에 등록 하려면 무료로 SendGrid 시작 을 참조 하세요.See Get Started with SendGrid for Free to register for a free SendGrid account.

IEmailSender 구현Implement IEmailSender

를 구현 하려면 IEmailSender 다음과 유사한 코드를 사용 하 여 서비스/emailsender .cs 를 만듭니다.To Implement IEmailSender, create Services/EmailSender.cs with code similar to the following:

using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.Extensions.Options;
using SendGrid;
using SendGrid.Helpers.Mail;
using System.Threading.Tasks;

namespace WebPWrecover.Services
{
    public class EmailSender : IEmailSender
    {
        public EmailSender(IOptions<AuthMessageSenderOptions> optionsAccessor)
        {
            Options = optionsAccessor.Value;
        }

        public AuthMessageSenderOptions Options { get; } //set only via Secret Manager

        public Task SendEmailAsync(string email, string subject, string message)
        {
            return Execute(Options.SendGridKey, subject, message, email);
        }

        public Task Execute(string apiKey, string subject, string message, string email)
        {
            var client = new SendGridClient(apiKey);
            var msg = new SendGridMessage()
            {
                From = new EmailAddress("Joe@contoso.com", "Joe Smith"),
                Subject = subject,
                PlainTextContent = message,
                HtmlContent = message
            };
            msg.AddTo(new EmailAddress(email));

            // Disable click tracking.
            // See https://sendgrid.com/docs/User_Guide/Settings/tracking.html
            msg.SetClickTracking(false, false);

            return client.SendEmailAsync(msg);
        }
    }
}

전자 메일을 지원 하도록 시작 구성Configure startup to support email

ConfigureServices Startup.cs 파일의 메서드에 다음 코드를 추가 합니다.Add the following code to the ConfigureServices method in the Startup.cs file:

  • EmailSender 임시 서비스로 추가 합니다.Add EmailSender as a transient service.
  • AuthMessageSenderOptions구성 인스턴스를 등록 합니다.Register the AuthMessageSenderOptions configuration instance.
public void ConfigureServices(IServiceCollection services)
{

    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));

    services.AddDefaultIdentity<IdentityUser>(config =>
    {
        config.SignIn.RequireConfirmedEmail = true;
    })
        .AddDefaultUI(UIFramework.Bootstrap4)
        .AddEntityFrameworkStores<ApplicationDbContext>();

    // requires
    // using Microsoft.AspNetCore.Identity.UI.Services;
    // using WebPWrecover.Services;
    services.AddTransient<IEmailSender, EmailSender>();
    services.Configure<AuthMessageSenderOptions>(Configuration);

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

계정 확인 및 암호 복구 사용Enable account confirmation and password recovery

템플릿에는 계정 확인 및 암호 복구를 위한 코드가 있습니다.The template has the code for account confirmation and password recovery. OnPostAsync 영역/ Identity /Pages/Account/Register.cshtml.cs에서 메서드를 찾습니다.Find the OnPostAsync method in Areas/Identity/Pages/Account/Register.cshtml.cs.

다음 줄을 주석으로 처리 하 여 새로 등록 된 사용자가 자동으로 로그인 하지 않도록 합니다.Prevent newly registered users from being automatically signed in by commenting out the following line:

await _signInManager.SignInAsync(user, isPersistent: false);

전체 메서드는 변경 된 줄이 강조 표시 된 상태로 표시 됩니다.The complete method is shown with the changed line highlighted:

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");
    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);
            var callbackUrl = Url.Page(
                "/Account/ConfirmEmail",
                pageHandler: null,
                values: new { 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>.");

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

등록, 전자 메일 확인 및 암호 재설정Register, confirm email, and reset password

웹 앱을 실행 하 고 계정 확인 및 암호 복구 흐름을 테스트 합니다.Run the web app, and test the account confirmation and password recovery flow.

  • 앱을 실행 하 고 새 사용자를 등록 합니다.Run the app and register a new user
  • 계정 확인 링크에 대 한 전자 메일을 확인 합니다.Check your email for the account confirmation link. 전자 메일을 받을 수 없는 경우 디버그 전자 메일 을 참조 하세요.See Debug email if you don't get the email.
  • 링크를 클릭 하 여 전자 메일을 확인 합니다.Click the link to confirm your email.
  • 전자 메일 및 암호를 사용 하 여 로그인 합니다.Sign in with your email and password.
  • 로그아웃합니다.Sign out.

관리 페이지 보기View the manage page

브라우저:  사용자 이름을 사용 하 여 브라우저 창에서 사용자 이름을 선택 합니다.Select your user name in the browser: browser window with user name

관리 페이지는 프로필 탭이 선택 된 상태로 표시 됩니다.The manage page is displayed with the Profile tab selected. 전자 메일 에는 전자 메일이 확인 되었다는 확인란이 표시 됩니다.The Email shows a check box indicating the email has been confirmed.

암호 재설정 테스트Test password reset

  • 로그인 하는 경우 로그 아웃을 선택 합니다.If you're signed in, select Logout.
  • 로그인 링크를 선택 하 고 암호를 잊으셨나요? 링크를 선택 합니다.Select the Log in link and select the Forgot your password? link.
  • 계정을 등록 하는 데 사용한 전자 메일을 입력 합니다.Enter the email you used to register the account.
  • 암호를 재설정 하는 링크가 포함 된 전자 메일이 전송 됩니다.An email with a link to reset your password is sent. 전자 메일을 확인 하 고 링크를 클릭 하 여 암호를 다시 설정 합니다.Check your email and click the link to reset your password. 암호를 성공적으로 재설정 한 후에는 전자 메일 및 새 암호로 로그인 할 수 있습니다.After your password has been successfully reset, you can sign in with your email and new password.

전자 메일 및 작업 시간 제한 변경Change email and activity timeout

기본 비활성 시간 제한은 14 일입니다.The default inactivity timeout is 14 days. 다음 코드는 비활성 시간 제한을 5 일로 설정 합니다.The following code sets the inactivity timeout to 5 days:

services.ConfigureApplicationCookie(o => {
    o.ExpireTimeSpan = TimeSpan.FromDays(5);
    o.SlidingExpiration = true;
});

모든 데이터 보호 토큰 변경 lifespansChange all data protection token lifespans

다음 코드는 모든 데이터 보호 토큰 제한 시간을 3 시간으로 변경 합니다.The following code changes all data protection tokens timeout period to 3 hours:

public void ConfigureServices(IServiceCollection services)
{

    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));

    services.AddDefaultIdentity<IdentityUser>(config =>
    {
        config.SignIn.RequireConfirmedEmail = true;
    })
        .AddDefaultUI(UIFramework.Bootstrap4)
        .AddEntityFrameworkStores<ApplicationDbContext>();

    services.Configure<DataProtectionTokenProviderOptions>(o =>
                o.TokenLifespan = TimeSpan.FromHours(3));

    services.AddTransient<IEmailSender, EmailSender>();
    services.Configure<AuthMessageSenderOptions>(Configuration);

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

기본 제공 Identity 사용자 토큰 ( AspNetCore/src/ Identity /Extensions.Core/src/TokenOptions.cs 참조)에는 1 일 시간 제한이있습니다.The built in Identity user tokens (see AspNetCore/src/Identity/Extensions.Core/src/TokenOptions.cs )have a one day timeout.

전자 메일 토큰 수명 변경Change the email token lifespan

Identity 사용자 토큰 의 기본 토큰 수명은 1 일입니다.The default token lifespan of the Identity user tokens is one day. 이 섹션에서는 전자 메일 토큰 수명을 변경 하는 방법을 보여 줍니다.This section shows how to change the email token lifespan.

사용자 지정 DataProtectorTokenProvider <TUser> 및를 추가 합니다 DataProtectionTokenProviderOptions .Add a custom DataProtectorTokenProvider<TUser> and DataProtectionTokenProviderOptions:

public class CustomEmailConfirmationTokenProvider<TUser> 
                                       : DataProtectorTokenProvider<TUser> where TUser : class
{
    public CustomEmailConfirmationTokenProvider(IDataProtectionProvider dataProtectionProvider,
        IOptions<EmailConfirmationTokenProviderOptions> options) 
                                                        : base(dataProtectionProvider, options)
    {

    }
}
public class EmailConfirmationTokenProviderOptions : DataProtectionTokenProviderOptions
{
    public EmailConfirmationTokenProviderOptions()
    {
        Name = "EmailDataProtectorTokenProvider";
        TokenLifespan = TimeSpan.FromHours(4);
    }
}

서비스 컨테이너에 사용자 지정 공급자를 추가 합니다.Add the custom provider to the service container:

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";                
    })
        .AddDefaultUI(UIFramework.Bootstrap4)
        .AddEntityFrameworkStores<ApplicationDbContext>();

    services.AddTransient<CustomEmailConfirmationTokenProvider<IdentityUser>>();
    services.AddTransient<IEmailSender, EmailSender>();            
    services.Configure<AuthMessageSenderOptions>(Configuration); // For SendGrid key.

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

전자 메일 다시 보내기 확인Resend email confirmation

GitHub 문제를 참조하세요.See this GitHub issue.

디버그 전자 메일Debug email

전자 메일을 사용할 수 없는 경우:If you can't get email working:

  • EmailSender.Execute가 호출 되었는지 확인 하려면에서 중단점을 설정 SendGridClient.SendEmailAsync 합니다.Set a breakpoint in EmailSender.Execute to verify SendGridClient.SendEmailAsync is called.
  • 비슷한 코드를 사용 하 여 전자 메일을 보내는 콘솔 앱 을 만듭니다 EmailSender.Execute .Create a console app to send email using similar code to EmailSender.Execute.
  • 전자 메일 작업 페이지를 검토 합니다.Review the Email Activity page.
  • 스팸 폴더를 확인 합니다.Check your spam folder.
  • 다른 전자 메일 공급자 (Microsoft, Yahoo, Gmail 등)에서 다른 전자 메일 별칭을 사용해 보세요.Try another email alias on a different email provider (Microsoft, Yahoo, Gmail, etc.)
  • 다른 전자 메일 계정으로 전송 해 보세요.Try sending to different email accounts.

보안 모범 사례 는 테스트 및 개발에서 프로덕션 암호를 사용 하지 않는 것입니다.A security best practice is to not use production secrets in test and development. Azure에 앱을 게시 하는 경우 Azure 웹 앱 포털에서 응용 프로그램 설정으로 SendGrid 암호를 설정할 수 있습니다.If you publish the app to Azure, you can set the SendGrid secrets as application settings in the Azure Web App portal. 구성 시스템은 환경 변수에서 키를 읽도록 설정 되어 있습니다.The configuration system is set up to read keys from environment variables.

소셜 및 로컬 로그인 계정 결합Combine social and local login accounts

이 섹션을 완료 하려면 먼저 외부 인증 공급자를 사용 하도록 설정 해야 합니다.To complete this section, you must first enable an external authentication provider. Facebook, Google 및 외부 공급자 인증을 참조 하세요.See Facebook, Google, and external provider authentication.

전자 메일 링크를 클릭 하 여 로컬 및 소셜 계정을 결합할 수 있습니다.You can combine local and social accounts by clicking on your email link. 다음 시퀀스에서는 " RickAndMSFT@gmail.com "이 (가) 로컬 로그인으로 먼저 생성 되지만 계정을 소셜 로그인으로 먼저 만든 다음 로컬 로그인을 추가할 수 있습니다.In the following sequence, "RickAndMSFT@gmail.com" is first created as a local login; however, you can create the account as a social login first, then add a local login.

웹 응용 프로그램: RickAndMSFT@gmail.com 사용자 인증 됨

관리 링크를 클릭 합니다.Click on the Manage link. 이 계정과 연결 된 0 외부 (소셜 로그인)를 확인 합니다.Note the 0 external (social logins) associated with this account.

뷰 관리

다른 로그인 서비스에 대 한 링크를 클릭 하 고 앱 요청을 수락 합니다.Click the link to another login service and accept the app requests. 다음 이미지에서 Facebook은 외부 인증 공급자입니다.In the following image, Facebook is the external authentication provider:

외부 로그인 보기 관리 Facebook 목록

두 계정을 결합 했습니다.The two accounts have been combined. 두 계정을 사용 하 여 로그인 할 수 있습니다.You are able to sign in with either account. 소셜 로그인 인증 서비스가 다운 되거나 소셜 계정에 대 한 액세스 권한이 손실 될 가능성이 있는 경우 사용자가 로컬 계정을 추가 하도록 할 수 있습니다.You might want your users to add local accounts in case their social login authentication service is down, or more likely they've lost access to their social account.

사이트에 사용자가 있는 후 계정 확인 사용Enable account confirmation after a site has users

사용자가 있는 사이트에서 계정 확인을 사용 하도록 설정 하면 모든 기존 사용자가 잠깁니다.Enabling account confirmation on a site with users locks out all the existing users. 계정이 확인 되지 않았기 때문에 기존 사용자가 잠깁니다.Existing users are locked out because their accounts aren't confirmed. 기존 사용자 잠금을 해결 하려면 다음 방법 중 하나를 사용 합니다.To work around existing user lockout, use one of the following approaches:

  • 기존 사용자를 모두 확인 된 것으로 표시 하도록 데이터베이스를 업데이트 합니다.Update the database to mark all existing users as being confirmed.
  • 기존 사용자를 확인 합니다.Confirm existing users. 예를 들어, 확인 링크가 포함 된 메일을 일괄 보냅니다.For example, batch-send emails with confirmation links.