ASP.NET Core でのアカウントの確認とパスワードの回復Account confirmation and password recovery in ASP.NET Core

Rick AndersonPonantJoe 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

認証を使用した web アプリの作成とテストCreate and test a web app with authentication

認証を使用して web アプリを作成するには、次のコマンドを実行します。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.
  • 左側の [ Personal data ] タブを選択し、[ 削除 ] を選択します。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. このサンプルでは、 サービス/認証の Enderoptions を作成します。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

とを SendGridUserSendGridKey シークレットマネージャーツールを使用して設定します。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 では、シークレットマネージャーは、キーと値のペアをディレクトリ内のファイル の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 を作成します。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

Startup.cs ファイルのメソッドに次のコードを追加し ConfigureServices ます。 Startup.csAdd 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

Web アプリを実行し、アカウントの確認とパスワードの回復フローをテストします。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;
});

すべてのデータ保護トークンの lifespans を変更するChange 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.

カスタム <TUser> DataProtectorTokenProviderとを追加し 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 Web アプリポータルで 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.

Web アプリケーション: 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 の一覧表示

2つのアカウントが結合されています。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

Web アプリとスキャフォールディングを作成する IdentityCreate a web app and scaffold Identity

認証を使用して web アプリを作成するには、次のコマンドを実行します。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.

データベースを表示する IdentityView 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 > View データ: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.

通常は、確認済みの電子メールを送信する前に、新しいユーザーが web サイトにデータを投稿できないようにします。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. このサンプルでは、 サービス/認証の Enderoptions を作成します。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

とを SendGridUserSendGridKey シークレットマネージャーツールを使用して設定します。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 では、シークレットマネージャーは、キーと値のペアをディレクトリ内のファイル の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 を作成します。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

Startup.cs ファイルのメソッドに次のコードを追加し ConfigureServices ます。 Startup.csAdd 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 Areas/ 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

Web アプリを実行し、アカウントの確認とパスワードの回復フローをテストします。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;
});

すべてのデータ保護トークンの lifespans を変更するChange 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.

カスタム <TUser> DataProtectorTokenProviderとを追加し 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 Web アプリポータルで 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.

Web アプリケーション: 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 の一覧表示

2つのアカウントが結合されています。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.