作成者: Rick Anderson、Ponant、Joe Audette
このチュートリアルでは、メールの確認とパスワードのリセットを備えた ASP.NET Core アプリを構築する方法について説明します。 このチュートリアルは、最初の記事 ではありません 。 次のことを理解している必要があります。
この記事のガイダンスを追加または置き換える Blazor ガイダンスについては、次のリソースを参照してください。
前提条件
認証を備えた Web アプリを作成してテストする
次のコマンドを実行して、認証を使用して Web アプリを作成します。
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 account インターフェイスがまだ実装されておらず、依存関係挿入コンテナーに登録されていないため、 リンクが表示されます。 詳細については、 RegisterConfirmation ソースを参照してください。
注
通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。
メール プロバイダーを構成する
このチュートリアルでは、Twilio 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では、シークレット マネージャーはキーと値のペアを ディレクトリの %APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId> ファイルに格納します。
secrets.json ファイルの内容は暗号化されません。 次のマークアップは 、secrets.json ファイルを示しています。
SendGridKey値は、この例から削除されます。
{
"SendGridKey": "<key removed>"
}
詳細については、ASP.NET Core の
SendGrid をインストールする
このチュートリアルでは、SendGrid を使ってメール通知を追加する方法について説明しますが、他のメール プロバイダーを使うこともできます。
SendGrid NuGet パッケージをインストールします。
パッケージ マネージャー コンソールから、次のコマンドを入力します。
Install-Package SendGrid
無料の SendGrid アカウントに登録するには、 無料の SendGrid Email API 試用版で送信を開始します。
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 がスキャフォールディングされている場合は、このセクションの手順をすべて実行してください。
Important
Account.RegisterConfirmation がスキャフォールディングされていない場合は、次の手順をスキップして、次のセクションに進んでください。
ユーザーは /Identity/Account/RegisterConfirmation ページにリダイレクトされ、アカウントを確認するためのリンクを選択できます。 既定の Account.RegisterConfirmation は、テスト にのみ 使用されます。 運用アプリでは、自動アカウント検証を無効にする必要があります。
確認済みのアカウントを要求し、登録時にすぐにサインインできないようにするには、スキャフォールディングされた Identity ファイルでを設定します。
// 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 が実装され、 依存関係挿入コンテナーに登録されたときに自動的に検出します。
登録し、メールを確認し、パスワードをリセットする
Web アプリを実行し、アカウント確認とパスワード回復のフローをテストします。
アプリを実行し、新しいユーザーを登録します。
アカウント確認用のリンクが記載されたメールをご確認ください。 メールが届かない場合は、トラブルシューティングの 「メールのデバッグ 」セクションを参照してください。
リンクを選択し、メールを確認します。
メールとパスワードを使ってサインインします。
サインアウトします。
パスワードのリセットをテストする
サインインしている場合は、[ログアウト] を選びます。
[ ログイン ] リンクを選択し、[パスワードを 忘れた 場合] リンクを選択します。
アカウントの登録に使ったメール アドレスを入力します。 アプリは、パスワードをリセットするためのリンクを含む電子メールを送信します。
送信された電子メール メッセージに移動します。
リンクを選択し、パスワードをリセットします。
パスワードが正常にリセットされたら、メールと新しいパスワードでサインインできます。
確認メールを再送信
このセクションでは、電子メール確認プロセスと関連タスクをサポートするコードについて説明します。
- まず、[ログイン] ページで [電子メールの再送信の確認] リンクを選択します。
メールとアクティビティのタイムアウトを変更する
非アクティブ状態の既定のタイムアウトは 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 日です。
次のコードは、電子メール トークンの有効期間を変更する方法を示しています。
カスタム DataProtectorTokenProvider<TUser> クラスと 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);
}
}
カスタム プロバイダーをサービス コンテナーに追加します。
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メソッドが呼び出されていることを確認します。メール アクティビティ ページを確認します。
迷惑メール フォルダーを確認します。
Microsoft、Yahoo、Gmail など、別のメール プロバイダーで別のメール エイリアスを試してください。
別のメール アカウントに送信してみます。
ヒント
セキュリティのベスト プラクティスは、テストと開発では運用用のシークレットを使用しないことです。 アプリを Azure に発行する場合は、Azure Web アプリ ポータルで SendGrid シークレットをアプリケーション設定として設定します。 構成システムは、環境変数からキーを読み取るように設定されています。
ソーシャルとローカルのログイン アカウントを結合する
このセクションを完了するには、最初に外部認証プロバイダーを有効にする必要があります。 詳細については、「 ASP.NET Core での Identity での外部ログイン プロバイダーの使用」を参照してください。
このシーケンスでは、 RickAndMSFT@gmail.com メール アドレスが最初にローカル ログインとして作成されます。 ただし、最初にソーシャル ログインとしてアカウントを作成してから、ローカル ログインを追加することができます。
ローカル アカウントとソーシャル アカウントを組み合わせるには、メール アドレス リンクを選択します。
[ アカウントの管理 ] ページで、[ 管理 ] リンクを選択します。
認証されたアカウントに関連付けられている外部 (ソーシャル ログイン) が現在ゼロ (0) であることに注意してください。
[ 外部ログインの管理 ] ページで、別のログイン サービスへのリンクを選択します。 サービス プロンプトに従い、アプリの要求を受け入れます。
次の図では、Facebook が外部認証プロバイダーとして追加されています。
ユーザーの電子メール アドレスの認証で、ローカル アカウントと外部 (ソーシャル) アカウントが組み合わせされるようになりました。 ユーザーは、どちらのアカウントでもサインインできます。
ヒント
ユーザーにアプリにローカル アカウントを追加することをお勧めします。 このアプローチは、ソーシャル ログイン認証サービスがダウンした場合や、ソーシャル アカウントへのアクセスが失われる場合に、継続的なアクセスを確保するのに役立ちます。
サイトにユーザーが存在するようになった後で、アカウントの確認を有効にする
既存のユーザーが存在するサイトでアカウントの確認を有効にした場合、アカウントが確認されないため、アカウントをロックアウトします。
既存のユーザー ロックアウトの問題を回避するには、次のいずれかの方法を使用します。
データベースを更新して、既存のすべてのユーザーを確認済みとしてマークします。
既存のユーザーを確認します。 たとえば、確認リンクを含むメールを一括送信します。
前提条件
認証を備えた Web アプリを作成してテストする
認証機能を備えた Web アプリを作成するには、次のコマンドを実行します。
dotnet new webapp -au Individual -uld -o WebPWrecover
cd WebPWrecover
dotnet run
アプリを実行し、[登録] リンクを選んで、ユーザーを登録します。 登録が済むと、メールの確認をシミュレートするためのリンクが含まれる /Identity/Account/RegisterConfirmation ページにリダイレクトされます。
-
Click here to confirm your accountリンクを選択します。 - [ログイン] リンクを選び、同じ資格情報でサインインします。
-
Hello YourEmail@provider.com!リンクを選ぶと、/Identity/Account/Manage/PersonalDataページにリダイレクトされます。 - 左側の [個人データ] タブを選び、[削除] を選びます。
メール プロバイダーを構成する
このチュートリアルでは、SendGrid を使ってメールを送信します。 他のメール プロバイダーを使ってもかまいません。 SendGrid または別のメール サービスを使ってメールを送信することをお勧めします。 SMTP では、メールがスパムとマークされないように構成することは困難です。
SendGrid アカウントでは、送信者の追加が必要になる場合があります。
セキュリティ保護されたメール キーをフェッチするためのクラスを作成します。 このサンプルでは、Services/AuthMessageSenderOptions.cs を作成します。
namespace WebPWrecover.Services;
public class AuthMessageSenderOptions
{
public string? SendGridKey { get; set; }
}
SendGrid のユーザー シークレットを構成する
secret-manager ツールを使用して、SendGridKeyを設定します。 次に例を示します。
dotnet user-secrets set SendGridKey <SG.key>
Successfully saved SendGridKey = SG.keyVal to the secret store.
Windows では、シークレット マネージャーによって、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}");
}
}
メールをサポートするためのスタートアップを構成する
ConfigureServices ファイルの Startup.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();
RegisterConfirmation をスキャフォールディングします
Scaffold Identity の手順に従って、Account\RegisterConfirmation をスキャフォールドします。
Account.RegisterConfirmation がスキャフォールディングされている場合に既定のアカウント検証を無効にする
Account.RegisterConfirmation がスキャフォールディングされている場合は、このセクションの手順をすべて実行してください。
Important
Account.RegisterConfirmation がスキャフォールディングされていない場合は、次の手順をスキップして、次のセクションに進んでください。
ユーザーは /Identity/Account/RegisterConfirmation ページにリダイレクトされ、アカウントを確認するためのリンクを選択できます。 既定の Account.RegisterConfirmation は、テスト にのみ 使用されます。 運用アプリでは、自動アカウント検証を無効にする必要があります。
確認済みのアカウントを要求し、登録時にすぐにサインインできないようにするには、スキャフォールディングされた Identity ファイルでを設定します。
// 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 が実装され、 依存関係挿入コンテナーに登録されたときに自動的に検出します。
登録し、メールを確認し、パスワードをリセットする
Web アプリを実行し、アカウント確認とパスワード回復のフローをテストします。
- アプリを実行して新しいユーザーを登録します
- アカウント確認用のリンクが記載されたメールをご確認ください。 メールを受信しない場合は、「メールをデバッグする」をご覧ください。
- リンクをクリックして、メールを確認します。
- メールとパスワードを使ってサインインします。
- サインアウトします。
パスワードのリセットをテストする
- サインインしている場合は、[ログアウト] を選びます。
- [ログイン] リンクを選び、[パスワードを忘れた場合] リンクを選びます。
- アカウントの登録に使ったメール アドレスを入力します。
- パスワードをリセットするためのリンクを含むメールが送信されます。 メールを確認し、リンクをクリックしてパスワードをリセットします。 パスワードが正常にリセットされたら、メール アドレスと新しいパスワードでサインインできます。
確認メールを再送信
.NET 5 以降で、[ログイン] ページの [電子メールの再送信] 確認リンクを選択します。
メールとアクティビティのタイムアウトを変更する
非アクティブ状態の既定のタイムアウトは 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 日です。 このセクションでは、メール トークンの有効期間を変更する方法について説明します。
カスタムの DataProtectorTokenProvider<TUser> と 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);
}
}
カスタム プロバイダーをサービス コンテナーに追加します。
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 Web アプリ ポータルで SendGrid シークレットをアプリケーション設定として設定します。 構成システムは、環境変数からキーを読み取るように設定されています。
ソーシャルとローカルのログイン アカウントを結合する
このセクションを完了するには、最初に外部認証プロバイダーを有効にする必要があります。 Facebook、Google、外部プロバイダーの認証に関するページをご覧ください。
メールのリンクをクリックして、ローカル アカウントとソーシャル アカウントを組み合わせることができます。 次のシーケンスでは、"RickAndMSFT@gmail.com" は最初にローカル ログインとして作成されています。ただし、アカウントを最初にソーシャル ログインとして作成してから、ローカル ログインを追加することもできます。
[管理] リンクをクリックします。 このアカウントに関連付けられている外部 (ソーシャル ログイン) が 0 であることに注意してください。
別のログイン サービスへのリンクをクリックし、アプリの要求を受け入れます。 次の図では、Facebook が外部認証プロバイダーです。
2 つのアカウントが結合されています。 いずれかのアカウントでサインインできます。 ソーシャル ログイン認証サービスがダウンしたときのため、またはさらに可能性が高いのはソーシャル アカウントにアクセスできなくなったときのために、ユーザーにローカル アカウントを追加させたいことがあります。
サイトにユーザーが存在するようになった後で、アカウントの確認を有効にする
ユーザーがいるサイトでアカウントの確認を有効にすると、すべての既存のユーザーがロックアウトされます。 既存のユーザーは、アカウントが確認されていないためにロックアウトされます。 既存のユーザーのロックアウトを回避するには、次のいずれかの方法を使用します。
- データベースを更新して、既存のすべてのユーザーを確認済みとしてマークします。
- 既存のユーザーを確認します。 たとえば、確認リンクを含むメールを一括送信します。
関連するコンテンツ
ASP.NET Core