Kontobestätigung und Kennwortwiederherstellung in ASP.NET Core Blazor
Hinweis
Dies ist nicht die neueste Version dieses Artikels. Die aktuelle Version finden Sie in der .NET 9-Version dieses Artikels.
Wichtig
Diese Informationen beziehen sich auf ein Vorabversionsprodukt, das vor der kommerziellen Freigabe möglicherweise noch wesentlichen Änderungen unterliegt. Microsoft gibt keine Garantie, weder ausdrücklich noch impliziert, hinsichtlich der hier bereitgestellten Informationen.
Die aktuelle Version finden Sie in der .NET 9-Version dieses Artikels.
In diesem Artikel wird erläutert, wie Sie eine ASP.NET Core-Blazor Web App mit E-Mail-Bestätigung und Kennwortwiederherstellung konfigurieren.
Hinweis
Dieser Artikel gilt nur für Blazor Web Apps. Informationen zum Implementieren der E-Mail-Bestätigung und kennwortwiederherstellung für eigenständige Blazor WebAssembly Apps mit ASP.NET Core Identityfinden Sie unter Kontobestätigung und Kennwortwiederherstellung in ASP.NET Core Blazor WebAssembly mit ASP.NET Core Identity.
Namespace
Im Beispiel in diesem Artikel wird der App-Namespace BlazorSample
verwendet. Aktualisieren Sie die Codebeispiele, um den Namespace Ihrer App zu verwenden.
Auswählen und Konfigurieren eines E-Mail-Anbieters
In diesem Artikel wird die Transactional API von Mailchimp über Mandrill.net zum Senden von E-Mails verwendet. Es wird empfohlen, einen E-Mail-Dienst statt SMTP zum Senden von E-Mails zu verwenden. SMTP ist schwer zu konfigurieren und zu schützen. Je nachdem, welchen E-Mail-Dienst Sie verwenden, befolgen Sie dessen Anleitungen für .NET-Apps, erstellen ein Konto, konfigurieren einen API-Schlüssel für den Dienst und installieren alle erforderlichen NuGet-Pakete.
Erstellen Sie eine Klasse, um den geheimen E-Mail-Anbieter-API-Schlüssel zu halten. Im Beispiel in diesem Artikel wird eine Klasse mit einem Namen AuthMessageSenderOptions
mit einer EmailAuthKey
Eigenschaft verwendet, um den Schlüssel zu halten.
AuthMessageSenderOptions.cs
:
namespace BlazorSample;
public class AuthMessageSenderOptions
{
public string? EmailAuthKey { get; set; }
}
Registrieren Sie die AuthMessageSenderOptions
-Konfigurationsinstanz in der Program
-Datei:
builder.Services.Configure<AuthMessageSenderOptions>(builder.Configuration);
Konfigurieren eines geheimen Schlüssels für den Sicherheitsschlüssel des E-Mail-Anbieters
Empfangen Sie den Sicherheitsschlüssel des E-Mail-Anbieters vom Anbieter, und verwenden Sie ihn in den folgenden Anleitungen.
Verwenden Sie entweder oder beide der folgenden Ansätze, um den geheimen Schlüssel für die App zu liefern:
- Geheime Manager-Tool: Das Tool "Geheimer Manager" speichert private Daten auf dem lokalen Computer und wird nur während der lokalen Entwicklung verwendet.
- Azure Key Vault: Sie können den geheimen Schlüssel in einem Schlüsseltresor speichern, um sie in jeder Umgebung zu verwenden, einschließlich für die Entwicklungsumgebung, wenn Sie lokal arbeiten. Einige Entwickler*innen ziehen es vor, für Staging- und Produktionsbereitstellungen Schlüsseltresore und für die lokale Entwicklung den Geheimnis-Manager zu verwenden.
Wir empfehlen dringend, Geheimnisse nicht im Projektcode oder in Konfigurationsdateien zu speichern. Verwenden Sie sichere Authentifizierungsflows, wie z. B. einen der in diesem Abschnitt beschriebenen Ansätze oder beide davon.
Geheimer Manager-Tool
Wenn das Projekt bereits für das Tool "Geheimer Manager" initialisiert wurde, verfügt es bereits über einen geheimen App-Bezeichner (<AppSecretsId>
) in der Projektdatei (.csproj
). In Visual Studio können Sie feststellen, ob die ID der geheimen App vorhanden ist, indem Sie sich den Eigenschaftenbereich ansehen, wenn das Projekt in Projektmappen-Explorer ausgewählt ist. Wenn die App nicht initialisiert wurde, führen Sie den folgenden Befehl in einer Befehlsshell aus, die im Verzeichnis des Projekts geöffnet wurde. In Visual Studio können Sie die PowerShell-Eingabeaufforderung für Entwickler verwenden.
dotnet user-secrets init
Legen Sie den API-Schlüssel mit dem Tool "Geheimer Manager" fest. Im folgenden Beispiel muss EmailAuthKey
der Schlüsselname übereinstimmen AuthMessageSenderOptions.EmailAuthKey
, und der Schlüssel wird durch den {KEY}
Platzhalter dargestellt. Führen Sie den folgenden Befehl mit dem API-Schlüssel aus:
dotnet user-secrets set "EmailAuthKey" "{KEY}"
Wenn Sie Visual Studio verwenden, können Sie bestätigen, dass der geheime Schlüssel festgelegt ist, indem Sie in Projektmappen-Explorer mit der rechten Maustaste auf das Serverprojekt klicken und "Benutzergeheimnisse verwalten" auswählen.
Weitere Informationen finden Sie unter Sichere Speicherung von App-Geheimnissen bei der Entwicklung in ASP.NET Core.
Warnung
Speichern Sie keine geheimen App-Schlüssel, Verbindungszeichenfolge s, Anmeldeinformationen, Kennwörter, persönliche Identifikationsnummern (PINs), privaten C#/.NET-Code oder private Schlüssel/Token im clientseitigen Code, der immer unsicher ist. In Test-/Staging- und Produktionsumgebungen sollten serverseitiger Blazor Code und Web-APIs sichere Authentifizierungsflüsse verwenden, die die Authentifizierung von Anmeldeinformationen innerhalb von Projektcode- oder Konfigurationsdateien vermeiden. Außerhalb der lokalen Entwicklungstests wird empfohlen, die Verwendung von Umgebungsvariablen zum Speichern vertraulicher Daten zu vermeiden, da Umgebungsvariablen nicht der sicherste Ansatz sind. Für lokale Entwicklungstests wird das Tool "Geheimer Manager" zum Sichern vertraulicher Daten empfohlen. Weitere Informationen finden Sie unter "Sichere Verwaltung vertraulicher Daten und Anmeldeinformationen".
Azure Key Vault
Azure Key Vault bietet einen sicheren Ansatz, um das Client-Geheimnis der App für die App bereitzustellen.
Informationen zum Erstellen eines Schlüsseltresors und zum Festlegen eines Geheimnisses finden Sie unter Informationen zu Azure Key Vault-Geheimnissen (Azure-Dokumentation) sowie in den darin aufgeführten Ressourcen für den Einstieg in Azure Key Vault. Zum Implementieren des in diesem Abschnitt aufgeführten Codes notieren Sie sich die URI des Schlüsseltresors und den geheimen Namen, wenn Sie in Azure den Schlüsseltresor und das Geheimnis erstellen. Wenn Sie die Zugriffsrichtlinie für das Geheimnis im Bereich Zugriffsrichtlinien festlegen:
- Es ist lediglich die Get secret-Erlaubnis erforderlich.
- Wählen Sie die Anwendung als Prinzipal für den geheimen Schlüssel aus.
Bestätigen Sie im Azure- oder Entra-Portal, dass der App Zugriff auf den geheimen Schlüssel gewährt wurde, den Sie für den E-Mail-Anbieterschlüssel erstellt haben.
Wichtig
Ein Schlüsseltresorgeheimnis wird mit einem Ablaufdatum erstellt. Achten Sie darauf, nachzuverfolgen, wann ein Schlüsseltresorgeheimnis abläuft, und erstellen Sie vor dem Ablauf dieses Datums ein neues Geheimnis für die App.
Fügen Sie dem Serverprojekt die folgende AzureHelper
Klasse hinzu. Die GetKeyVaultSecret
-Methode ruft einen geheimen Schlüssel aus einem Schlüsseltresor ab. Passen Sie den Namespace (BlazorSample.Helpers
) an Ihr Projekt-Namespace-Schema an.
Helpers/AzureHelper.cs
:
using Azure;
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
namespace BlazorSample.Helpers;
public static class AzureHelper
{
public static string GetKeyVaultSecret(string tenantId, string vaultUri, string secretName)
{
DefaultAzureCredentialOptions options = new()
{
// Specify the tenant ID to use the dev credentials when running the app locally
// in Visual Studio.
VisualStudioTenantId = tenantId,
SharedTokenCacheTenantId = tenantId
};
var client = new SecretClient(new Uri(vaultUri), new DefaultAzureCredential(options));
var secret = client.GetSecretAsync(secretName).Result;
return secret.Value.Value;
}
}
Wenn Dienste in der Program
-Datei des Serverprojekts registriert sind, abrufen und binden Sie das Geheimnis mit der Optionskonfiguration:
var tenantId = builder.Configuration.GetValue<string>("AzureAd:TenantId")!;
var vaultUri = builder.Configuration.GetValue<string>("AzureAd:VaultUri")!;
var emailAuthKey = AzureHelper.GetKeyVaultSecret(
tenantId, vaultUri, "EmailAuthKey");
var authMessageSenderOptions =
new AuthMessageSenderOptions() { EmailAuthKey = emailAuthKey };
builder.Configuration.GetSection(authMessageSenderOptions.EmailAuthKey)
.Bind(authMessageSenderOptions);
Wenn Sie die Umgebung steuern möchten, in der der vorangehende Code ausgeführt wird, z. B. um die lokale Ausführung des Codes zu vermeiden, da Sie sich entschieden haben, das tool Geheimen Manager für die lokale Entwicklung zu verwenden, können Sie den vorherigen Code in eine bedingte Anweisung einschließen, die die Umgebung überprüft:
if (!context.HostingEnvironment.IsDevelopment())
{
...
}
Bestätigen Sie im Abschnitt AzureAd
von appsettings.json
im Serverprojekt, ob die Entra-ID der App TenantId
vorhanden ist, und fügen Sie den folgenden VaultUri
Konfigurationsschlüssel und -wert hinzu, sofern er noch nicht vorhanden ist:
"VaultUri": "{VAULT URI}"
Im vorherigen Beispiel entspricht der {VAULT URI}
-Platzhalter der Schlüsseltresor-URI. Fügen Sie den nachgestellten Schrägstrich in die URI ein.
Beispiel:
"VaultUri": "https://contoso.vault.azure.net/"
Die Konfiguration wird verwendet, um die Bereitstellung dedizierter Schlüsseltresore und geheimer Namensdaten basierend auf den Umgebungskonfigurationsdateien der App zu erleichtern. Sie können z. B. unterschiedliche Konfigurationswerte für appsettings.Development.json
in der Entwicklung, appsettings.Staging.json
beim Staging und appsettings.Production.json
für die Produktionsbereitstellung bereitstellen. Weitere Informationen finden Sie unter ASP.NET Core Blazor Configuration.
Implementieren Sie IEmailSender
.
Das folgende Beispiel basiert auf der Transactional API von Mailchimp unter Verwendung von Mandrill.net. Informationen zum Implementieren des Sendens einer E-Mail-Nachricht finden Sie in der Dokumentation eines anderen Anbieters.
Fügen Sie dem Projekt das Mandrill.net NuGet-Paket hinzu.
Fügen Sie die folgende EmailSender
Klasse hinzu, um sie zu implementieren IEmailSender<TUser>. Im folgenden Beispiel ApplicationUser
ist ein IdentityUser. Das HTML-Markup für Nachrichten kann weiter angepasst werden. Solange der message
übergebene Wert MandrillMessage
mit dem <
Zeichen beginnt, geht die Mandrill.net-API davon aus, dass der Nachrichtentext in HTML verfasst ist.
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);
}
}
Hinweis
Textkörperinhalte für Nachrichten erfordern möglicherweise eine spezielle Codierung für den E-Mail-Dienstanbieter. Wenn Links im Nachrichtentext in der E-Mail-Nachricht nicht befolgt werden können, wenden Sie sich an die Dokumentation des Dienstanbieters, um das Problem zu beheben.
Konfigurieren der App zur Unterstützung von E-Mails
Ändern Sie in der Datei Program
die Implementierung des E-Mail-Absenders in EmailSender
:
- builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSender>();
+ builder.Services.AddSingleton<IEmailSender<ApplicationUser>, EmailSender>();
Entfernen Sie IdentityNoOpEmailSender
(Components/Account/IdentityNoOpEmailSender.cs
) aus der App.
Entfernen Sie in der Komponente RegisterConfirmation
(Components/Account/Pages/RegisterConfirmation.razor
) den Bedingungsblock aus dem @code
-Block, der überprüft, ob EmailSender
ein IdentityNoOpEmailSender
-Element ist:
- else if (EmailSender is IdentityNoOpEmailSender)
- {
- ...
- }
Entfernen Sie in der Komponente RegisterConfirmation
ebenfalls das Razor-Markup und den Code zum Überprüfen des Felds emailConfirmationLink
, und lassen Sie nur die Zeile, in der oder die Benutzer*in angewiesen wird, seine oder ihre E-Mail zu überprüfen.
- @if (emailConfirmationLink is not null)
- {
- ...
- }
- else
- {
<p>Please check your email to confirm your account.</p>
- }
@code {
- private string? emailConfirmationLink;
...
}
Aktivieren der Kontobestätigung, nachdem eine Website Benutzer*innen enthält
Durch Aktivieren der Kontobestätigung auf einer Website mit Benutzer*innen werden alle vorhandenen Benutzer*innen gesperrt. Vorhandene Benutzer werden gesperrt, da ihre Konten nicht bestätigt wurden. Verwenden Sie einen der folgenden Ansätze, um die Sperrung vorhandener Benutzer*innen zu umgehen:
- Aktualisieren Sie die Datenbank, um alle vorhandenen Benutzer*innen als bestätigt zu kennzeichnen.
- Bestätigen Sie die vorhandenen Benutzer*innen. Senden Sie beispielsweise Batch-E-Mails mit Bestätigungslinks.
Timeout für E-Mails und Aktivitäten
Der Standardzeitraum für die Inaktivität bis zum Timeout beträgt 14 Tage. Der folgende Code legt das Inaktivitätstimeout auf fünf Tage mit variablem Ablauf fest:
builder.Services.ConfigureApplicationCookie(options => {
options.ExpireTimeSpan = TimeSpan.FromDays(5);
options.SlidingExpiration = true;
});
Ändern der Lebensdauer aller ASP.NET Core-Datenschutztoken
Der folgende Code ändert den Timeoutzeitraum für alle Datenschutztoken auf drei Stunden:
builder.Services.Configure<DataProtectionTokenProviderOptions>(options =>
options.TokenLifespan = TimeSpan.FromHours(3));
Die integrierten Identity Benutzertoken (AspNetCore/src/Identity/Extensions.Core/src/TokenOptions.cs) verfügen über ein Tagestimeout.
Hinweis
Dokumentationslinks zur .NET-Referenzquelle laden in der Regel den Standardbranch des Repositorys, der die aktuelle Entwicklung für das nächste Release von .NET darstellt. Um ein Tag für ein bestimmtes Release auszuwählen, wählen Sie diesen mit der Dropdownliste Switch branches or tags (Branches oder Tags wechseln) aus. Weitere Informationen finden Sie unter How to select a version tag of ASP.NET Core source code (dotnet/AspNetCore.Docs #26205) (Auswählen eines Versionstags von ASP.NET Core-Quellcode (dotnet/AspNetCore.Docs #26205)).
Ändern der Lebensdauer von E-Mail-Token
Die Standardlebensdauer von Identity-Benutzertoken beträgt einen Tag.
Hinweis
Dokumentationslinks zur .NET-Referenzquelle laden in der Regel den Standardbranch des Repositorys, der die aktuelle Entwicklung für das nächste Release von .NET darstellt. Um ein Tag für ein bestimmtes Release auszuwählen, wählen Sie diesen mit der Dropdownliste Switch branches or tags (Branches oder Tags wechseln) aus. Weitere Informationen finden Sie unter How to select a version tag of ASP.NET Core source code (dotnet/AspNetCore.Docs #26205) (Auswählen eines Versionstags von ASP.NET Core-Quellcode (dotnet/AspNetCore.Docs #26205)).
Um die Lebensdauer des E-Mail-Tokens zu ändern, fügen Sie eine benutzerdefinierte und DataProtectorTokenProvider<TUser>eine .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);
}
}
Konfigurieren Sie die Dienste in der Datei Program
für die Verwendung des benutzerdefinierten Tokenanbieters:
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>>();
Problembehandlung
Wenn E-Mails nicht funktionieren:
- Legen Sie einen Breakpoint in
EmailSender.Execute
fest, um zu überprüfen, obSendEmailAsync
aufgerufen wird. - Erstellen Sie eine Konsolen-App, um E-Mails mithilfe von Code zu senden, der
EmailSender.Execute
zum Debuggen des Problems ähnelt. - Überprüfen Sie die E-Mail-Verlaufsseiten des Kontos auf der Website des E-Mail-Anbieters.
- Überprüfen Sie Ihren Spamordner auf Nachrichten.
- Versuchen Sie es mit einem anderen E-Mail-Alias bei einem anderen E-Mail-Anbieter, zum Beispiel Microsoft, Yahoo oder Gmail.
- Versuchen Sie, die E-Mail an andere E-Mail-Konten zu senden.