ASP.NET Core Blazor でのアカウントの確認とパスワードの回復
Note
これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 9 バージョンを参照してください。
重要
この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。
現在のリリースについては、この記事の .NET 9 バージョンを参照してください。
この記事では、メールの確認とパスワードの回復を備えた ASP.NET Core Blazor Web App を構築する方法について説明します。
Note
この記事は、 Blazor Web Appにのみ適用されます。 ASP.NET Core Identity を使用したスタンドアロン Blazor WebAssembly アプリの電子メール確認とパスワード回復を実装するには、ASP.NET Core Identityを使用した ASP.NET Core Blazor WebAssemblyでのアカウントの確認とパスワードの回復に関するを参照してください。
名前空間
この記事の例で使用されているアプリの名前空間は BlazorSample
です。 アプリの名前空間を使用するようにコードの例を更新します。
メール プロバイダーを選択して構成する
この記事では、Mailchimp のトランザクション API を使用して Mandrill.net 経由でメールを送信します。 メール送信には、SMTP ではなく、メール サービスを使うことをお勧めします。 SMTP を適切に構成してセキュリティで保護することは困難です。 どのメール サービスを使用する場合でも、.NET アプリのガイダンスにアクセスし、アカウントを作成し、サービスの API キーを構成し、必要な NuGet パッケージをインストールします。
シークレット電子メール プロバイダー API キーを保持するクラスを作成します。 この記事の例では、EmailAuthKey
プロパティを持つ AuthMessageSenderOptions
という名前のクラスを使用してキーを保持します。
AuthMessageSenderOptions.cs
:
namespace BlazorSample;
public class AuthMessageSenderOptions
{
public string? EmailAuthKey { get; set; }
}
Program
ファイルに AuthMessageSenderOptions
構成インスタンスを登録します。
builder.Services.Configure<AuthMessageSenderOptions>(builder.Configuration);
プロバイダーのセキュリティ キーのユーザー シークレットを構成する
プロジェクトが既に Secret Manager ツール用に初期化されている場合プロジェクト ファイル (.csproj
) にアプリ シークレット識別子 (<AppSecretsId>
) が既に存在します。 Visual Studio では、ソリューション エクスプローラーでプロジェクトが選択されているときに Properties パネルを見て、アプリ シークレット ID が存在するかどうかを確認できます。 アプリが初期化されていない場合は、プロジェクトのディレクトリに対して開かれたコマンド シェルで次のコマンドを実行します。 Visual Studio では、開発者 PowerShell コマンド プロンプトを使用できます。
dotnet user-secrets init
Secret Manager ツールを使用して API キーを設定します。 次の例では、キー名はAuthMessageSenderOptions.EmailAuthKey
と一致するようにEmailAuthKey
され、キーは {KEY}
プレースホルダーで表されます。 API キーを使用して次のコマンドを実行します。
dotnet user-secrets set "EmailAuthKey" "{KEY}"
Visual Studio を使用している場合は、ソリューション エクスプローラーでサーバー プロジェクトを右クリックし、[ユーザー シークレットの管理] 選択することで、シークレットが設定されていることを確認。
詳細については、「ASP.NET Core での開発におけるアプリ シークレットの安全な保存」を参照してください。
警告
アプリ シークレット、接続文字列、資格情報、パスワード、個人識別番号 (PIN)、プライベート C#/.NET コード、秘密キー/トークンをクライアント側コードに格納しないでください。これは安全ではありません。 テスト/ステージング環境と運用環境では、サーバー側の Blazor コードと Web API は、プロジェクト コードまたは構成ファイル内で資格情報を維持しないように、セキュリティで保護された認証フローを使用する必要があります。 ローカル開発テスト以外では、環境変数が最も安全なアプローチではないため、環境変数を使用して機密データを格納しないようにすることをお勧めします。 ローカル開発テストでは、機密データをセキュリティで保護するために、 Secret Manager ツール をお勧めします。 詳細については、「 機密データと資格情報を安全に管理するを参照してください。
IEmailSender
を実装する
次の例は、Mandrill.net を使用する Mailchimp のトランザクション API に基づいています。 別のプロバイダーについては、電子メール メッセージの送信を実装する方法に関するドキュメントを参照してください。
Mandrill.net NuGet パッケージをプロジェクトに追加します。
次の EmailSender
クラスを追加して、 IEmailSender<TUser>を実装します。 次の例では、 ApplicationUser
は IdentityUserです。 メッセージ HTML マークアップをさらにカスタマイズできます。 MandrillMessage
に渡されるmessage
が<
文字で始まる限り、Mandrill.net API はメッセージ本文が HTML で構成されていることを前提としています。
Components/Account/EmailSender.cs
:
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Mandrill;
using Mandrill.Model;
using BlazorSample.Data;
namespace BlazorSample.Components.Account;
public class EmailSender(IOptions<AuthMessageSenderOptions> optionsAccessor,
ILogger<EmailSender> logger) : IEmailSender<ApplicationUser>
{
private readonly ILogger logger = logger;
public AuthMessageSenderOptions Options { get; } = optionsAccessor.Value;
public Task SendConfirmationLinkAsync(AppUser user, string email,
string confirmationLink) => SendEmailAsync(email, "Confirm your email",
"<html lang=\"en\"><head></head><body>Please confirm your account by " +
$"<a href='{confirmationLink}'>clicking here</a>.</body></html>");
public Task SendPasswordResetLinkAsync(AppUser user, string email,
string resetLink) => SendEmailAsync(email, "Reset your password",
"<html lang=\"en\"><head></head><body>Please reset your password by " +
$"<a href='{resetLink}'>clicking here</a>.</body></html>");
public Task SendPasswordResetCodeAsync(AppUser user, string email,
string resetCode) => SendEmailAsync(email, "Reset your password",
"<html lang=\"en\"><head></head><body>Please reset your password " +
$"using the following code:<br>{resetCode}</body></html>");
public async Task SendEmailAsync(string toEmail, string subject, string message)
{
if (string.IsNullOrEmpty(Options.EmailAuthKey))
{
throw new Exception("Null EmailAuthKey");
}
await Execute(Options.EmailAuthKey, subject, message, toEmail);
}
public async Task Execute(string apiKey, string subject, string message,
string toEmail)
{
var api = new MandrillApi(apiKey);
var mandrillMessage = new MandrillMessage("sarah@contoso.com", toEmail,
subject, message);
await api.Messages.SendAsync(mandrillMessage);
logger.LogInformation("Email to {EmailAddress} sent!", toEmail);
}
}
Note
メッセージの本文コンテンツには、メール サービス プロバイダーの特別なエンコードが必要な場合があります。 メッセージ本文のリンクを電子メール メッセージでフォローできない場合は、サービス プロバイダーのドキュメントを参照して問題のトラブルシューティングを行ってください。
メールをサポートするようにアプリを構成する
Program
ファイルで、メール送信者の実装を EmailSender
に変更します。
- builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSender>();
+ builder.Services.AddSingleton<IEmailSender<ApplicationUser>, EmailSender>();
アプリから IdentityNoOpEmailSender
(Components/Account/IdentityNoOpEmailSender.cs
) を削除します。
RegisterConfirmation
コンポーネント (Components/Account/Pages/RegisterConfirmation.razor
) で、EmailSender
が IdentityNoOpEmailSender
であるかをチェックする @code
ブロックの条件付きブロックを削除します。
- else if (EmailSender is IdentityNoOpEmailSender)
- {
- ...
- }
また、RegisterConfirmation
コンポーネントで、emailConfirmationLink
フィールドをチェックするための Razor マークアップとコードを削除し、メールをチェックするようにユーザーに指示する行だけを残します。
- @if (emailConfirmationLink is not null)
- {
- ...
- }
- else
- {
<p>Please check your email to confirm your account.</p>
- }
@code {
- private string? emailConfirmationLink;
...
}
サイトにユーザーがいる用になった後でアカウントの確認を有効にする
ユーザーがいるサイトでアカウントの確認を有効にすると、すべての既存のユーザーがロックアウトされます。 既存のユーザーは、アカウントが確認されていないためにロックアウトされます。 既存のユーザーのロックアウトを回避するには、次のいずれかの方法を使用します。
- データベースを更新して、既存のすべてのユーザーを確認済みとしてマークします。
- 既存のユーザーを確認します。 たとえば、確認リンクを含むメールを一括送信します。
メールとアクティビティのタイムアウト
非アクティブ状態の既定のタイムアウトは 14 日です。 次のコードでは、スライド式有効期限を有効にし、非アクティブ状態のタイムアウトを 5 日に設定します。
builder.Services.ConfigureApplicationCookie(options => {
options.ExpireTimeSpan = TimeSpan.FromDays(5);
options.SlidingExpiration = true;
});
すべての ASP.NET Core データ保護トークンの有効期限を変更する
次のコードでは、データ保護トークンのタイムアウト期間が 3 時間に変更されます。
builder.Services.Configure<DataProtectionTokenProviderOptions>(options =>
options.TokenLifespan = TimeSpan.FromHours(3));
組み込みの Identity ユーザー トークン (AspNetCore/src/Identity/Extensions.Core/src/TokenOptions.cs) には、1 日のタイムアウト があります。
Note
通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。
メール トークンの有効期間を変更する
Identity ユーザー トークンの既定のトークン有効期間は 1 日です。
Note
通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。
電子メール トークンの有効期間を変更するには、カスタム DataProtectorTokenProvider<TUser> と DataProtectionTokenProviderOptionsを追加します。
CustomTokenProvider.cs
:
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
namespace BlazorSample;
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 class CustomPasswordResetTokenProvider<TUser>
: DataProtectorTokenProvider<TUser> where TUser : class
{
public CustomPasswordResetTokenProvider(
IDataProtectionProvider dataProtectionProvider,
IOptions<PasswordResetTokenProviderOptions> options,
ILogger<DataProtectorTokenProvider<TUser>> logger)
: base(dataProtectionProvider, options, logger)
{
}
}
public class PasswordResetTokenProviderOptions :
DataProtectionTokenProviderOptions
{
public PasswordResetTokenProviderOptions()
{
Name = "PasswordResetDataProtectorTokenProvider";
TokenLifespan = TimeSpan.FromHours(3);
}
}
Program
ファイルでカスタム トークン プロバイダーを使用するようにサービスを構成します。
builder.Services.AddIdentityCore<ApplicationUser>(options =>
{
options.SignIn.RequireConfirmedAccount = true;
options.Tokens.ProviderMap.Add("CustomEmailConfirmation",
new TokenProviderDescriptor(
typeof(CustomEmailConfirmationTokenProvider<ApplicationUser>)));
options.Tokens.EmailConfirmationTokenProvider =
"CustomEmailConfirmation";
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddSignInManager()
.AddDefaultTokenProviders();
builder.Services
.AddTransient<CustomEmailConfirmationTokenProvider<ApplicationUser>>();
トラブルシューティング
メールが機能しない場合:
EmailSender.Execute
にブレークポイントを設定して、SendEmailAsync
が呼び出されることを確認します。- 問題をデバッグするために、
EmailSender.Execute
のようなコードを使用してメールを送信するコンソール アプリを作成します。 - メール プロバイダーの Web サイトでアカウントのメール履歴ページを確認します。
- メッセージがないか迷惑メール フォルダーを確認します。
- 別のメール プロバイダー (Microsoft、Yahoo、Gmail など) で別のメール エイリアスを試します。
- 別のメール アカウントに送信してみます。
その他のリソース
ASP.NET Core