Account confirmation and password recovery in ASP.NET Core (Kontobestätigung und Kennwortwiederherstellung in ASP.NET Core)
Von Rick Anderson, Ponant und Joe Audette
In diesem Tutorial wird gezeigt, wie Sie eine ASP.NET Core-App mit E-Mail-Bestätigung und Kennwortzurücksetzung erstellen. Dieses Tutorial ist kein Anfangsthema. Sie sollten mit den folgenden Punkten vertraut sein:
Voraussetzungen
Erstellen und Testen einer Web-App mit Authentifizierung
Führen Sie die folgenden Befehle aus, um eine Web-App mit Authentifizierung zu erstellen.
dotnet new webapp -au Individual -o WebPWrecover
cd WebPWrecover
dotnet run
Registrieren eines Benutzers mit simulierter E-Mail-Bestätigung
Führen Sie die App aus, wählen Sie den Link Registrieren aus, und registrieren Sie einen Benutzer. Nach der Registrierung werden Sie zur Seite zu /Identity/Account/RegisterConfirmation
weitergeleitet, die einen Link zum Simulieren der E-Mail-Bestätigung enthält:
- Klicken Sie auf den Link
Click here to confirm your account
(Zentralisierte Protokollierung). - Wählen Sie den Link Anmelden aus, und melden Sie sich mit den gleichen Anmeldeinformationen an.
- Wählen Sie den
Hello YourEmail@provider.com!
Link aus, der/Identity/Account/Manage/PersonalData
zur Seite weitergeleitet wird. - Wählen Sie links die Registerkarte Persönliche Daten und dann Löschen aus.
Der Click here to confirm your account
Link wird angezeigt, da kein IEmailSender implementiert und im Verzeichniseinschleusungscontainer registriert wurde. Weitere Informationen finden Sie in der RegisterConfirmation-Quelle.
Konfigurieren eines E-Mail-Anbieters
In diesem Tutorial wird SendGrid zum Senden von E-Mails verwendet. Zum Senden einer E-Mail ist ein SendGrid-Konto und ein SendGrid-Schlüssel erforderlich. Andere E-Mail-Anbieter. Es wird empfohlen, SendGrid oder einen anderen E-Mail-Dienst anstelle von SMTP zu verwenden, um E-Mails zu senden. SMTP ist schwer zu schützen und richtig einzurichten.
Für das SendGrid-Konto ist möglicherweise das Hinzufügen eines Absenders erforderlich.
Erstellen Sie eine Klasse, um den sicheren E-Mail-Schlüssel abzurufen. Erstellen Sie Services/AuthMessageSenderOptions.cs
für dieses Beispiel :
namespace WebPWrecover.Services;
public class AuthMessageSenderOptions
{
public string? SendGridKey { get; set; }
}
Konfigurieren von SendGrid-Benutzergeheimnissen
Legen Sie den SendGridKey
mit dem Tool secret-manager fest. Beispiel:
dotnet user-secrets set SendGridKey <key>
Successfully saved SendGridKey to the secret store.
Unter Windows speichert Secret Manager Schlüssel-Wert-Paare in einer secrets.json
Datei im %APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId>
Verzeichnis.
Der Inhalt der secrets.json
Datei ist nicht verschlüsselt. Das folgende Markup zeigt die secrets.json
Datei. Der SendGridKey
Wert wurde entfernt.
{
"SendGridKey": "<key removed>"
}
Weitere Informationen finden Sie unter Optionenmuster und Konfiguration.
Installieren von SendGrid
In diesem Tutorial wird gezeigt, wie Sie E-Mail-Benachrichtigungen über SendGrid hinzufügen, aber andere E-Mail-Anbieter können verwendet werden.
Installieren Sie das SendGrid
NuGet-Paket:
Geben Sie in der Paket-Manager-Konsole den folgenden Befehl ein:
Install-Package SendGrid
Informationen zum Registrieren eines kostenlosen SendGrid-Kontos finden Sie unter Erste Schritte mit SendGrid kostenlos .
Implementieren von IEmailSender
Um zu implementieren IEmailSender
, erstellen Sie Services/EmailSender.cs
mit Code ähnlich dem folgenden:
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}");
}
}
Konfigurieren der App für die Unterstützung von E-Mails
Fügen Sie der Datei Program.cs
den folgenden Code hinzu:
- Fügen Sie als vorübergehenden Dienst hinzu
EmailSender
. - Registrieren Sie die
AuthMessageSenderOptions
Konfigurationsinstanz.
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();
Deaktivieren der Standardkontoüberprüfung, wenn Account.RegisterConfirmation gerüstet wurde
Dieser Abschnitt gilt nur, wenn Account.RegisterConfirmation
ein Gerüst erstellt wird. Überspringen Sie diesen Abschnitt, wenn Sie nicht gerüstet Account.RegisterConfirmation
haben.
Der Benutzer wird zu dem Account.RegisterConfirmation
weitergeleitet, wo er einen Link auswählen kann, um das Konto bestätigen zu lassen. Der Standardwert Account.RegisterConfirmation
wird nur für Tests verwendet. Die automatische Kontoüberprüfung sollte in einer Produktions-App deaktiviert werden.
Um ein bestätigtes Konto zu erfordern und eine sofortige Anmeldung bei der Registrierung zu verhindern, legen Sie in der Gerüstdatei /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs
folgendes festDisplayConfirmAccountLink = false
:
// 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();
}
}
}
Dieser Schritt ist nur erforderlich, wenn Account.RegisterConfirmation
ein Gerüst erstellt wird. Die nicht gerüstete RegisterConfirmation erkennt automatisch, wenn ein IEmailSender implementiert und im Container für die Verzeichniseinschleusung registriert wurde.
Registrieren, Bestätigen der E-Mail und Zurücksetzen des Kennworts
Führen Sie die Web-App aus, und testen Sie den Kontobestätigungs- und Kennwortwiederherstellungsflow.
- Ausführen der App und Registrieren eines neuen Benutzers
- Überprüfen Sie Ihre E-Mail auf den Link zur Kontobestätigung. Weitere Informationen finden Sie unter Debuggen von E-Mails , wenn Sie die E-Mail nicht erhalten.
- Klicken Sie auf den Link, um Ihre E-Mail zu bestätigen.
- Melden Sie sich mit Ihrer E-Mail-Adresse und Ihrem Kennwort an.
- Melden Sie sich ab.
Testen der Kennwortzurücksetzung
- Wenn Sie angemeldet sind, wählen Sie Abmelden aus.
- Wählen Sie den Link Anmelden aus, und wählen Sie den Link Kennwort vergessen? aus.
- Geben Sie die E-Mail ein, die Sie zum Registrieren des Kontos verwendet haben.
- Eine E-Mail mit einem Link zum Zurücksetzen Ihres Kennworts wird gesendet. Überprüfen Sie Ihre E-Mail-Adresse, und klicken Sie auf den Link, um Ihr Kennwort zurückzusetzen. Nachdem Ihr Kennwort erfolgreich zurückgesetzt wurde, können Sie sich mit Ihrer E-Mail-Adresse und dem neuen Kennwort anmelden.
E-Mail-Bestätigung erneut senden
Wählen Sie auf der Seite Anmeldung den Link E-Mail-Bestätigung erneut senden aus.
Ändern des E-Mail- und Aktivitätstimeouts
Das Standardmäßige Inaktivitätstimeout beträgt 14 Tage. Der folgende Code legt das Inaktivitätstimeout auf 5 Tage fest:
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
Ändern aller Lebensdauern von Datenschutztoken
Der folgende Code ändert den Timeoutzeitraum für alle Datenschutztoken auf 3 Stunden:
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.
Die integrierten Identity Benutzertoken (siehe AspNetCore/src/Identity/Extensions.Core/src/TokenOptions.cs ) weisen ein Timeout von einem Tag auf.
Ändern der Lebensdauer des E-Mail-Tokens
Die Standardtokenlebensdauer der Identity Benutzertoken beträgt einen Tag. In diesem Abschnitt wird gezeigt, wie Sie die Lebensdauer des E-Mail-Tokens ändern.
Fügen Sie einen benutzerdefinierten DataProtectorTokenProvider<TUser> und DataProtectionTokenProviderOptionshinzu:
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);
}
}
Fügen Sie dem Dienstcontainer den benutzerdefinierten Anbieter hinzu:
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.
Debuggen von E-Mails
Wenn E-Mails nicht funktionieren können:
- Legen Sie einen Haltepunkt fest
EmailSender.Execute
, um zu überprüfen, obSendGridClient.SendEmailAsync
aufgerufen wird. - Erstellen Sie eine Konsolen-App zum Senden von E-Mails mit ähnlichem Code wie .
EmailSender.Execute
- Überprüfen Sie die Seite Email Aktivität.
- Überprüfen Sie Ihren Spamordner.
- Versuchen Sie einen anderen E-Mail-Alias bei einem anderen E-Mail-Anbieter (Microsoft, Yahoo, Gmail usw.)
- Versuchen Sie, an verschiedene E-Mail-Konten zu senden.
Eine bewährte Sicherheitsmethode besteht darin, keine Produktionsgeheimnisse bei Test und Entwicklung zu verwenden. Wenn Sie die App in Azure veröffentlichen, legen Sie die SendGrid-Geheimnisse im Azure-Web-App-Portal als Anwendungseinstellungen fest. Das Konfigurationssystem ist zum Lesen von Schlüsseln aus Umgebungsvariablen eingerichtet.
Kombinieren von Sozialen und lokalen Anmeldekonten
Um diesen Abschnitt abzuschließen, müssen Sie zuerst einen externen Authentifizierungsanbieter aktivieren. Siehe Facebook-, Google- und externe Anbieterauthentifizierung.
Sie können lokale und soziale Konten kombinieren, indem Sie auf Ihren E-Mail-Link klicken. In der folgenden Sequenz wird "RickAndMSFT@gmail.com" zuerst als lokale Anmeldung erstellt. Sie können das Konto jedoch zuerst als Social Media-Anmeldung erstellen und dann eine lokale Anmeldung hinzufügen.
Klicken Sie auf den Link Verwalten . Notieren Sie sich die 0 externen (Social-Media-Anmeldungen), die diesem Konto zugeordnet sind.
Klicken Sie auf den Link zu einem anderen Anmeldedienst, und akzeptieren Sie die App-Anforderungen. In der folgenden Abbildung ist Facebook der externe Authentifizierungsanbieter:
Die beiden Konten wurden kombiniert. Sie können sich mit beiden Konten anmelden. Möglicherweise möchten Sie, dass Ihre Benutzer lokale Konten hinzufügen, falls ihr Authentifizierungsdienst für die soziale Anmeldung ausgefallen ist oder sie wahrscheinlich den Zugriff auf ihr Social Media-Konto verloren haben.
Aktivieren der Kontobestätigung, nachdem auf einer Website Benutzer vorhanden sind
Wenn Sie die Kontobestätigung auf einer Website mit Benutzern aktivieren, werden alle vorhandenen Benutzer gesperrt. Vorhandene Benutzer werden gesperrt, da ihre Konten nicht bestätigt werden. Verwenden Sie einen der folgenden Ansätze, um vorhandene Benutzersperren zu umgehen:
- Aktualisieren Sie die Datenbank, um alle vorhandenen Benutzer als bestätigt zu markieren.
- Bestätigen Sie vorhandene Benutzer. Beispielsweise senden Sie E-Mails im Batch mit Bestätigungslinks.
Voraussetzungen
Erstellen und Testen einer Web-App mit Authentifizierung
Führen Sie die folgenden Befehle aus, um eine Web-App mit Authentifizierung zu erstellen.
dotnet new webapp -au Individual -uld -o WebPWrecover
cd WebPWrecover
dotnet run
Führen Sie die App aus, wählen Sie den Link Registrieren aus, und registrieren Sie einen Benutzer. Nach der Registrierung werden Sie zur Seite zu /Identity/Account/RegisterConfirmation
weitergeleitet, die einen Link zum Simulieren der E-Mail-Bestätigung enthält:
- Klicken Sie auf den Link
Click here to confirm your account
(Zentralisierte Protokollierung). - Wählen Sie den Link Anmelden aus, und melden Sie sich mit den gleichen Anmeldeinformationen an.
- Wählen Sie den
Hello YourEmail@provider.com!
Link aus, der Sie zur/Identity/Account/Manage/PersonalData
Seite weiterleitet. - Wählen Sie links die Registerkarte Persönliche Daten und dann Löschen aus.
Konfigurieren eines E-Mail-Anbieters
In diesem Tutorial wird SendGrid zum Senden von E-Mails verwendet. Sie können andere E-Mail-Anbieter verwenden. Es wird empfohlen, zum Senden von E-Mails SendGrid oder einen anderen E-Mail-Dienst zu verwenden. SMTP ist schwer zu konfigurieren, sodass E-Mails nicht als Spam gekennzeichnet werden.
Für das SendGrid-Konto ist möglicherweise das Hinzufügen eines Absenders erforderlich.
Erstellen Sie eine Klasse, um den sicheren E-Mail-Schlüssel abzurufen. Erstellen Sie Services/AuthMessageSenderOptions.cs
für dieses Beispiel :
namespace WebPWrecover.Services;
public class AuthMessageSenderOptions
{
public string? SendGridKey { get; set; }
}
Konfigurieren von SendGrid-Benutzergeheimnissen
Legen Sie den SendGridKey
mit dem Tool secret-manager fest. Beispiel:
dotnet user-secrets set SendGridKey <SG.key>
Successfully saved SendGridKey = SG.keyVal to the secret store.
Unter Windows speichert Secret Manager Schlüssel-Wert-Paare in einer secrets.json
Datei im %APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId>
Verzeichnis.
Der Inhalt der secrets.json
Datei ist nicht verschlüsselt. Das folgende Markup zeigt die secrets.json
Datei. Der SendGridKey
Wert wurde entfernt.
{
"SendGridKey": "<key removed>"
}
Weitere Informationen finden Sie unter Optionenmuster und Konfiguration.
Installieren von SendGrid
In diesem Tutorial wird gezeigt, wie Sie E-Mail-Benachrichtigungen über SendGrid hinzufügen, aber Sie können E-Mails mithilfe von SMTP und anderen Mechanismen senden.
Installieren Sie das SendGrid
NuGet-Paket:
Geben Sie in der Paket-Manager-Konsole den folgenden Befehl ein:
Install-Package SendGrid
Informationen zum Registrieren eines kostenlosen SendGrid-Kontos finden Sie unter Erste Schritte mit SendGrid kostenlos .
Implementieren von IEmailSender
Um zu implementieren IEmailSender
, erstellen Sie Services/EmailSender.cs
mit Code ähnlich dem folgenden:
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}");
}
}
Konfigurieren des Startvorgangs zur Unterstützung von E-Mails
Fügen Sie der -Methode in Startup.cs
der Datei den ConfigureServices
folgenden Code hinzu:
- Fügen Sie als vorübergehenden Dienst hinzu
EmailSender
. - Registrieren Sie die
AuthMessageSenderOptions
Konfigurationsinstanz.
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();
Scaffold RegisterConfirmation
Befolgen Sie die Anweisungen für Gerüst Identity und Gerüst Account\RegisterConfirmation
.
Deaktivieren der Standardkontoüberprüfung, wenn Account.RegisterConfirmation gerüstet wurde
Dieser Abschnitt gilt nur, wenn Account.RegisterConfirmation
ein Gerüst erstellt wird. Überspringen Sie diesen Abschnitt, wenn Sie nicht gerüstet Account.RegisterConfirmation
haben.
Der Benutzer wird zu dem Account.RegisterConfirmation
weitergeleitet, wo er einen Link auswählen kann, um das Konto bestätigen zu lassen. Der Standardwert Account.RegisterConfirmation
wird nur für Tests verwendet. Die automatische Kontoüberprüfung sollte in einer Produktions-App deaktiviert werden.
Um ein bestätigtes Konto zu erfordern und eine sofortige Anmeldung bei der Registrierung zu verhindern, legen Sie in der Gerüstdatei /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs
folgendes festDisplayConfirmAccountLink = false
:
// 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();
}
}
}
Dieser Schritt ist nur erforderlich, wenn Account.RegisterConfirmation
ein Gerüst erstellt wird. Die nicht gerüstete RegisterConfirmation erkennt automatisch, wenn ein IEmailSender implementiert und im Container für die Verzeichniseinschleusung registriert wurde.
Registrieren, Bestätigen der E-Mail und Zurücksetzen des Kennworts
Führen Sie die Web-App aus, und testen Sie den Kontobestätigungs- und Kennwortwiederherstellungsflow.
- Ausführen der App und Registrieren eines neuen Benutzers
- Überprüfen Sie Ihre E-Mail auf den Link zur Kontobestätigung. Weitere Informationen finden Sie unter Debuggen von E-Mails , wenn Sie die E-Mail nicht erhalten.
- Klicken Sie auf den Link, um Ihre E-Mail zu bestätigen.
- Melden Sie sich mit Ihrer E-Mail-Adresse und Ihrem Kennwort an.
- Melden Sie sich ab.
Testen der Kennwortzurücksetzung
- Wenn Sie angemeldet sind, wählen Sie Abmelden aus.
- Wählen Sie den Link Anmelden aus, und wählen Sie den Link Kennwort vergessen? aus.
- Geben Sie die E-Mail ein, die Sie zum Registrieren des Kontos verwendet haben.
- Eine E-Mail mit einem Link zum Zurücksetzen Ihres Kennworts wird gesendet. Überprüfen Sie Ihre E-Mail-Adresse, und klicken Sie auf den Link, um Ihr Kennwort zurückzusetzen. Nachdem Ihr Kennwort erfolgreich zurückgesetzt wurde, können Sie sich mit Ihrer E-Mail-Adresse und dem neuen Kennwort anmelden.
E-Mail-Bestätigung erneut senden
Wählen Sie in ASP.NET Core 5.0 und höher auf der Seite Anmeldung den Link E-Mail-Bestätigung erneut senden aus.
Ändern des E-Mail- und Aktivitätstimeouts
Das Standardmäßige Inaktivitätstimeout beträgt 14 Tage. Der folgende Code legt das Inaktivitätstimeout auf 5 Tage fest:
services.ConfigureApplicationCookie(o => {
o.ExpireTimeSpan = TimeSpan.FromDays(5);
o.SlidingExpiration = true;
});
Ändern aller Lebensdauern von Datenschutztoken
Der folgende Code ändert den Timeoutzeitraum für alle Datenschutztoken auf 3 Stunden:
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();
}
Die integrierten Identity Benutzertoken (siehe AspNetCore/src/Identity/Extensions.Core/src/TokenOptions.cs ) weisen ein Timeout von einem Tag auf.
Ändern der Lebensdauer des E-Mail-Tokens
Die Standardtokenlebensdauer der Identity Benutzertoken beträgt einen Tag. In diesem Abschnitt wird gezeigt, wie Sie die Lebensdauer des E-Mail-Tokens ändern.
Fügen Sie eine benutzerdefinierte DataProtectorTokenProvider<TUser> und DataProtectionTokenProviderOptionshinzu:
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);
}
}
Fügen Sie dem Dienstcontainer den benutzerdefinierten Anbieter hinzu:
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();
}
Debuggen von E-Mails
Wenn E-Mails nicht funktionieren können:
- Legen Sie einen Haltepunkt in
EmailSender.Execute
fest, um zu überprüfen, obSendGridClient.SendEmailAsync
aufgerufen wird. - Erstellen Sie eine Konsolen-App zum Senden von E-Mails mit ähnlichem Code wie
EmailSender.Execute
. - Überprüfen Sie die Seite Email Aktivität.
- Überprüfen Sie Ihren Spamordner.
- Versuchen Sie es mit einem anderen E-Mail-Alias bei einem anderen E-Mail-Anbieter (Microsoft, Yahoo, Gmail usw.)
- Versuchen Sie, an andere E-Mail-Konten zu senden.
Eine bewährte Sicherheitsmethode besteht darin, keine Produktionsgeheimnisse in Tests und in der Entwicklung zu verwenden. Wenn Sie die App in Azure veröffentlichen, legen Sie die SendGrid-Geheimnisse im Azure-Web-App-Portal als Anwendungseinstellungen fest. Das Konfigurationssystem ist zum Lesen von Schlüsseln aus Umgebungsvariablen eingerichtet.
Kombinieren von sozialen und lokalen Anmeldekonten
Um diesen Abschnitt abzuschließen, müssen Sie zunächst einen externen Authentifizierungsanbieter aktivieren. Weitere Informationen finden Sie unter Authentifizierung von Facebook, Google und externen Anbietern.
Sie können lokale und soziale Konten kombinieren, indem Sie auf Ihren E-Mail-Link klicken. In der folgenden Sequenz wird "RickAndMSFT@gmail.com" zuerst als lokaler Anmeldename erstellt. Sie können das Konto jedoch zuerst als Anmeldung für soziale Netzwerke erstellen und dann eine lokale Anmeldung hinzufügen.
Klicken Sie auf den Link Verwalten . Notieren Sie sich die 0 externen (social logins), die diesem Konto zugeordnet sind.
Klicken Sie auf den Link zu einem anderen Anmeldedienst, und akzeptieren Sie die App-Anforderungen. In der folgenden Abbildung ist Facebook der externe Authentifizierungsanbieter:
Die beiden Konten wurden kombiniert. Sie können sich mit beiden Konten anmelden. Möglicherweise möchten Sie, dass Ihre Benutzer lokale Konten hinzufügen, falls ihr Authentifizierungsdienst für soziale Netzwerke ausgefallen ist oder wahrscheinlicher, dass sie den Zugriff auf ihr Social Media-Konto verloren haben.
Aktivieren der Kontobestätigung, nachdem eine Website Benutzer enthält
Durch aktivieren der Kontobestätigung auf einer Website mit Benutzern werden alle vorhandenen Benutzer gesperrt. Vorhandene Benutzer werden gesperrt, weil ihre Konten nicht bestätigt werden. Verwenden Sie einen der folgenden Ansätze, um vorhandene Benutzersperrungen zu umgehen:
- Aktualisieren Sie die Datenbank, um alle vorhandenen Benutzer als bestätigt zu markieren.
- Bestätigen vorhandener Benutzer. Beispielsweise Batch-E-Mails mit Bestätigungslinks senden.