Account confirmation and password recovery in ASP.NET Core (Conferma dell'account e recupero della password in ASP.NET Core)

Di Rick Anderson, Ponant e Joe Audette

Questa esercitazione illustra come creare un'app ASP.NET Core con la conferma tramite posta elettronica e la reimpostazione della password. Questo tutorial non è un articolo per principianti. È necessario avere familiarità con:

Per Blazor indicazioni su come aggiungere o sostituire le linee guida contenute in questo articolo, vedere le risorse seguenti:

Prerequisiti

Creare e testare un'app Web con l'autenticazione

Eseguire i comandi seguenti per creare un'app Web con autenticazione:

dotnet new webapp -au Individual -o WebPWrecover
cd WebPWrecover
dotnet run

Registrare un utente con conferma tramite posta elettronica simulata

Eseguire l'app, selezionare il collegamento Registra e registrare un utente.

Al termine della registrazione, si viene reindirizzati alla /Identity/Account/RegisterConfirmation pagina, che contiene un collegamento per simulare la conferma tramite posta elettronica.

  1. Selezionare il collegamento Click here to confirm your account.

  2. Selezionare il link Login ed effettuare l'accesso con le stesse credenziali.

  3. Selezionare il Hello YourEmail@provider.com! collegamento che reindirizza alla /Identity/Account/Manage/PersonalData pagina.

  4. Selezionare la scheda Dati personali e quindi selezionare Elimina.

Il Click here to confirm your account collegamento viene visualizzato perché l'interfaccia IEmailSender non è ancora implementata e registrata con il contenitore di dependency injection. Per ulteriori informazioni, vedere il codice sorgente RegisterConfirmation.

Nota

I collegamenti della documentazione al codice sorgente di riferimento di .NET in genere caricano il ramo predefinito del repository, che rappresenta lo sviluppo corrente per la prossima versione di .NET. Per selezionare un tag per una versione specifica, utilizza il menu a discesa Switch branches or tags. Per altre informazioni, vedere How to select a version tag of ASP.NET Core source code (dotnet/AspNetCore.Docs #26205) (Come selezionare un tag di versione del codice sorgente di ASP.NET - dotnet/AspNetCore.Docs #26205).

Configurare un provider di posta elettronica

In questa esercitazione, Twilio SendGrid viene usato per inviare messaggi di posta elettronica. Per inviare un messaggio di posta elettronica, è necessario un account SendGrid e una chiave. È consigliabile usare SendGrid o un altro servizio di posta elettronica per inviare messaggi di posta elettronica anziché SMTP. SMTP è difficile da proteggere e configurare correttamente.

L'account SendGrid potrebbe richiedere l'aggiunta di un mittente.

Creare una classe per recuperare la chiave di posta elettronica sicura. Per questo esempio, creare il file Services/AuthMessageSenderOptions.cs :

namespace WebPWrecover.Services;

public class AuthMessageSenderOptions
{
    public string? SendGridKey { get; set; }
}

Configurare i segreti utente di SendGrid

Imposta SendGridKey valore utilizzando lo strumento secret-manager. Ad esempio:

dotnet user-secrets set SendGridKey <key>

Successfully saved SendGridKey to the secret store.

In Windows Secret Manager archivia le coppie chiavi/valore in un file secrets.json nella directory %APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId>.

Il contenuto del filesecrets.json non è crittografato. Il markup seguente illustra il file secrets.json . Il SendGridKey valore viene rimosso dall'esempio.

{
  "SendGridKey": "<key removed>"
}

Per altre informazioni, vedere il modello Options e Configuration in ASP.NET Core.

Installare SendGrid

Questa esercitazione illustra come aggiungere notifiche di posta elettronica tramite SendGrid, ma è possibile usare altri provider di posta elettronica.

Installare il SendGrid pacchetto NuGet:

Nella console di Gestione pacchetti immettere il comando seguente:

Install-Package SendGrid

Per registrarsi per un account SendGrid gratuito, iniziare a inviare con una versione di valutazione gratuita dell'API SendGrid Email.

Implementare IEmailSender

Per implementare l'interfaccia IEmailSender , creare il file Services/EmailSender.cs con codice simile all'esempio seguente:

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}");
    }
}

Configurare l'app per supportare la posta elettronica

Aggiungere il codice seguente al file Program.cs , che esegue le attività seguenti:

  • Aggiunge l'istanza EmailSender come servizio temporaneo.
  • Registra l'istanza di configurazione 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();

Disabilitare la verifica predefinita dell'account quando Account.RegisterConfirmation viene generato tramite scaffolding

Se Account.RegisterConfirmation è stato generato tramite scaffolding, completare le istruzioni in questa sezione.

Important

Se Account.RegisterConfirmationnon è stato eseguito lo scaffolding, ignorare le istruzioni seguenti e continuare con la sezione successiva.

L'utente viene reindirizzato alla /Identity/Account/RegisterConfirmation pagina in cui è possibile selezionare un collegamento per confermare l'account. Il valore predefinito Account.RegisterConfirmation viene usato solo per i test. La verifica automatica dell'account deve essere disabilitata in un'app di produzione.

Per richiedere un account confermato e impedire l'accesso immediato al momento della registrazione, impostare DisplayConfirmAccountLink = false nel file /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs generato tramite scaffolding:

// 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();
        }
    }
}

Questo passaggio è necessario solo quando Account.RegisterConfirmation viene generato mediante scaffolding.

RegisterConfirmation non sottoposto a scaffolding rileva automaticamente quando un IEmailSender viene implementato e registrato con il contenitore di inserimento delle dipendenze.

Registrare, confermare la posta elettronica e reimpostare la password

Eseguire l'app Web e testare il flusso di conferma e ripristino delle password dell'account.

  1. Eseguire l'app e registrare un nuovo utente.

  2. Controllare l'indirizzo di posta elettronica per il collegamento di conferma dell'account. Se non si riceve il messaggio di posta elettronica, vedere la sezione Debug e-mail per la risoluzione dei problemi.

  3. Selezionare il collegamento e confermare il messaggio di posta elettronica.

  4. Accedere con l'indirizzo di posta elettronica e la password.

  5. Disconnettersi.

Testare la reimpostazione della password

  1. Se è stato eseguito l'accesso, selezionare Disconnetti.

  2. Selezionare il collegamento Accedi e quindi selezionare il collegamento Password dimenticata?

  3. Immettere il messaggio di posta elettronica usato per registrare l'account. L'app invia un messaggio di posta elettronica con un collegamento per reimpostare la password.

  4. Passare al messaggio di posta elettronica inviato.

  5. Selezionare il collegamento e reimpostare la password.

Dopo la reimpostazione della password, è possibile accedere con il messaggio di posta elettronica e la nuova password.

Inviare di nuovo la conferma tramite posta elettronica

Questa sezione descrive il codice che supporta il processo di conferma tramite posta elettronica e le attività correlate.

  • Per iniziare, selezionare il collegamento Invia di nuovo conferma tramite posta elettronica nella pagina Di accesso .

Modifica il timeout dell'email e dell'attività

Il timeout di inattività predefinito è 14 giorni. Il codice seguente imposta il timeout di inattività su cinque giorni:

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

Modificare tutta la durata dei token di protezione dei dati

Il codice seguente modifica il periodo di timeout per tutti i token di protezione dei dati a tre ore:

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.

I token utente predefiniti Identity (vedere l'origine AspNetCore/src/Identity/Extensions.Core/src/TokenOptions.cs ) hanno un timeout di un giorno.

Modificare la durata del token di posta elettronica

La durata predefinita dei token Identity utente è di un giorno.

Il codice seguente illustra come modificare la durata del token di posta elettronica.

Aggiungi una classe personalizzata DataProtectorTokenProvider<TUser> e una classe personalizzata 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);
    }
}

Aggiungere il provider personalizzato al contenitore del servizio:

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.

Eseguire il debug della posta elettronica

Se il processo di posta elettronica non funziona come previsto, provare a seguire questa procedura di risoluzione dei problemi:

  • Impostare un punto di interruzione nel EmailSender.Execute metodo e verificare che venga chiamato il SendGridClient.SendEmailAsync metodo .

  • Creare un'app console per inviare messaggi di posta elettronica usando codice simile a EmailSender.Execute.

  • Esaminare la pagina Attività di posta elettronica.

  • Controllare la cartella della posta indesiderata.

  • Provare un altro alias di posta elettronica su un provider di posta elettronica diverso, ad esempio Microsoft, Yahoo, Gmail e così via.

  • Provare a inviare a account di posta elettronica diversi.

Tip

Una procedura consigliata per la sicurezza consiste nel non usare segreti di produzione in fase di test e sviluppo. Se si pubblica l'app in Azure, impostare i segreti SendGrid come impostazioni dell'applicazione nel portale di App Web di Azure. Il sistema di configurazione è configurato per leggere le chiavi dalle variabili di ambiente.

Combinazione di account di accesso social e locali

Per completare questa sezione, è prima necessario abilitare un provider di autenticazione esterno. Per maggiori informazioni, vedere Utilizzare i provider di accesso esterni con Identity in ASP.NET Core.

In questa sequenza, l'indirizzo RickAndMSFT@gmail.com di posta elettronica viene prima creato come account di accesso locale. Tuttavia, è possibile creare prima l'account come account di accesso di social networking e quindi aggiungere un account di accesso locale.

  1. Per combinare account locali e social, seleziona il collegamento dell'indirizzo e-mail.

    Screenshot che mostra come selezionare il collegamento indirizzo di posta elettronica per l'utente autenticato nell'app Web.

  2. Nella pagina Gestisci l'account selezionare il collegamento Gestisci .

    Si noti che all'account autenticato sono attualmente associati zero (0) esterni (account di accesso social).

    Schermata che mostra zero accessi esterni (accessi social) associati all'account autenticato. Il collegamento «Gestione» è evidenziato.

  3. Nella pagina Gestisci account di accesso esterni selezionare il collegamento a un altro servizio di accesso. Seguire le richieste del servizio e accettare le richieste dell'app.

    Nell'immagine seguente Facebook viene aggiunto come provider di autenticazione esterno:

    Schermata che mostra Facebook aggiunto come accesso esterno (social) per l'account autenticato.

L'autenticazione per l'indirizzo di posta elettronica dell'utente ora combina account locali ed esterni (social). L'utente può accedere con uno dei due account.

Tip

È consigliabile consigliare agli utenti di aggiungere un account locale all'app. Questo approccio può contribuire a garantire un accesso continuativo nel caso in cui il servizio di autenticazione dell'accesso social non sia disponibile oppure si perda l'accesso al proprio account social.

Abilitare la conferma dell'account dopo che un sito ha utenti

Se si abilita la conferma dell'account su un sito con utenti esistenti, si impedisce loro l'accesso perché i loro account non sono confermati.

Per risolvere il problema del blocco utente esistente, usare uno degli approcci seguenti:

  • Aggiornare il database per contrassegnare tutti gli utenti esistenti come confermati.

  • Confermare gli utenti esistenti. Ad esempio, inviare messaggi di posta elettronica in batch con collegamenti di conferma.

Prerequisiti

.NET Core 3.0 o versione successiva SDK

Creare e testare un'app Web con l'autenticazione

Eseguire i comandi seguenti per creare un'app Web con autenticazione.

dotnet new webapp -au Individual -uld -o WebPWrecover
cd WebPWrecover
dotnet run

Eseguire l'app, selezionare il collegamento Registra e registrare un utente. Dopo la registrazione, si viene reindirizzati alla pagina /Identity/Account/RegisterConfirmation, che contiene un collegamento per simulare la conferma dell’e-mail:

  • Selezionare il collegamento Click here to confirm your account.
  • Selezionare il link Login ed effettuare l'accesso con le stesse credenziali.
  • Selezionare il Hello YourEmail@provider.com! collegamento, che reindirizza alla /Identity/Account/Manage/PersonalData pagina.
  • Selezionare la scheda Dati personali a sinistra e quindi selezionare Elimina.

Configurare un provider di posta elettronica

In questa esercitazione SendGrid viene usato per inviare messaggi di posta elettronica. È possibile usare altri provider di posta elettronica. È consigliabile usare SendGrid o un altro servizio di posta elettronica per inviare messaggi di posta elettronica. SMTP è difficile da configurare in modo che la posta non sia contrassegnata come posta indesiderata.

L'account SendGrid potrebbe richiedere l'aggiunta di un mittente.

Creare una classe per recuperare la chiave di posta elettronica sicura. Per questo esempio, creare Services/AuthMessageSenderOptions.cs:

namespace WebPWrecover.Services;

public class AuthMessageSenderOptions
{
    public string? SendGridKey { get; set; }
}

Configurare i segreti utente di SendGrid

Imposta il SendGridKey con lo strumento secret-manager. Ad esempio:

dotnet user-secrets set SendGridKey <SG.key>

Successfully saved SendGridKey = SG.keyVal to the secret store.

In Windows Secret Manager archivia coppie chiave/valore in un secrets.json file nella %APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId> directory.

Il contenuto del secrets.json file non è crittografato. Il markup seguente illustra il secrets.json file. Il SendGridKey valore è stato rimosso.

{
  "SendGridKey": "<key removed>"
}

Per altre informazioni, vedere Modello e configurazione delle opzioni.

Installare SendGrid

Questa esercitazione illustra come aggiungere notifiche di posta elettronica tramite SendGrid, ma è possibile inviare messaggi di posta elettronica usando SMTP e altri meccanismi.

Installare il SendGrid pacchetto NuGet:

Nella console di Gestione pacchetti immettere il comando seguente:

Install-Package SendGrid

Vedere Introduzione a SendGrid gratuitamente per registrarsi per un account SendGrid gratuito.

Implementare IEmailSender

Per implementare IEmailSender, creare Services/EmailSender.cs con codice simile al seguente:

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}");
    }
}

Configurare l'avvio per supportare la posta elettronica

Aggiungere il codice seguente al ConfigureServices metodo nel Startup.cs file :

  • Aggiungere EmailSender come servizio temporaneo.
  • Registrare l'istanza di configurazione 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();

Impalcatura ConfermaRegistrazione

Seguire le istruzioni per Scaffold Identity e scaffold Account\RegisterConfirmation.

Disabilitare la verifica predefinita dell'account quando Account.RegisterConfirmation viene generato tramite scaffolding

Se Account.RegisterConfirmation è stato generato tramite scaffolding, completare le istruzioni in questa sezione.

Important

Se Account.RegisterConfirmationnon è stato eseguito lo scaffolding, ignorare le istruzioni seguenti e continuare con la sezione successiva.

L'utente viene reindirizzato alla /Identity/Account/RegisterConfirmation pagina in cui è possibile selezionare un collegamento per confermare l'account. Il valore predefinito Account.RegisterConfirmation viene usato solo per i test. La verifica automatica dell'account deve essere disabilitata in un'app di produzione.

Per richiedere un account confermato e impedire l'accesso immediato al momento della registrazione, impostare DisplayConfirmAccountLink = false nel file /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs generato tramite scaffolding:

// 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();
        }
    }
}

Questo passaggio è necessario solo quando Account.RegisterConfirmation viene generato mediante scaffolding.

RegisterConfirmation non sottoposto a scaffolding rileva automaticamente quando un IEmailSender viene implementato e registrato con il contenitore di inserimento delle dipendenze.

Registrare, confermare la posta elettronica e reimpostare la password

Eseguire l'app Web e testare il flusso di conferma e ripristino delle password dell'account.

  • Eseguire l'app e registrare un nuovo utente
  • Controllare l'indirizzo di posta elettronica per il collegamento di conferma dell'account. Vedere Eseguire il debug del messaggio di posta elettronica se non si riceve il messaggio di posta elettronica.
  • Fare clic sul collegamento per confermare il messaggio di posta elettronica.
  • Accedere con l'indirizzo di posta elettronica e la password.
  • Disconnettersi.

Testare la reimpostazione della password

  • Se è stato eseguito l'accesso, selezionare Disconnetti.
  • Selezionare il collegamento Accedi e selezionare il collegamento Password dimenticata?
  • Immettere il messaggio di posta elettronica usato per registrare l'account.
  • Viene inviato un messaggio di posta elettronica con un collegamento per reimpostare la password. Controllare il messaggio di posta elettronica e fare clic sul collegamento per reimpostare la password. Dopo la reimpostazione della password, è possibile accedere con il messaggio di posta elettronica e la nuova password.

Inviare di nuovo la conferma tramite posta elettronica

In .NET 5 o versione successiva selezionare il collegamento Invia di nuovo conferma tramite posta elettronica nella pagina Di accesso .

Modifica il timeout dell'email e dell'attività

Il timeout di inattività predefinito è 14 giorni. Il codice seguente imposta il timeout di inattività su 5 giorni:

services.ConfigureApplicationCookie(o => {
    o.ExpireTimeSpan = TimeSpan.FromDays(5);
    o.SlidingExpiration = true;
});

Modificare tutta la durata dei token di protezione dei dati

Il codice seguente modifica il periodo di timeout di tutti i token di protezione dei dati a 3 ore:

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();
}

I token utente predefiniti Identity (vedere AspNetCore/src//IdentityExtensions.Core/src/TokenOptions.cs )hanno un timeout di un giorno.

Modificare la durata del token di posta elettronica

La durata predefinita dei token Identity utente è di un giorno. Questa sezione illustra come modificare la durata del token di posta elettronica.

Aggiungere un oggetto personalizzato DataProtectorTokenProvider<TUser> e 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);
    }
}

Aggiungere il provider personalizzato al contenitore del servizio:

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();
}

Eseguire il debug della posta elettronica

Se non è possibile ricevere messaggi di posta elettronica funzionanti:

  • Imposta un breakpoint in EmailSender.Execute per verificare che SendGridClient.SendEmailAsync venga chiamato.
  • Creare un'app console per inviare messaggi di posta elettronica usando codice simile a EmailSender.Execute.
  • Esaminare la pagina Attività di posta elettronica.
  • Controllare la cartella della posta indesiderata.
  • Provare un altro alias di posta elettronica su un provider di posta elettronica diverso (Microsoft, Yahoo, Gmail e così via)
  • Provare a inviare a account di posta elettronica diversi.

Una procedura consigliata per la sicurezza consiste nel non usare segreti di produzione in fase di test e sviluppo. Se si pubblica l'app in Azure, impostare i segreti SendGrid come impostazioni dell'applicazione nel portale di App Web di Azure. Il sistema di configurazione è configurato per leggere le chiavi dalle variabili di ambiente.

Associare account di accesso tramite social network e account locali

Per completare questa sezione, è prima necessario abilitare un provider di autenticazione esterno. Vedere Facebook, Google e autenticazione del provider esterno.

È possibile combinare account locali e social facendo clic sul collegamento di posta elettronica. Nella sequenza seguente "RickAndMSFT@gmail.com" viene prima creato come account di accesso locale. Tuttavia, è possibile creare prima l'account come account di accesso di social networking e quindi aggiungere un account di accesso locale.

Applicazione Web: RickAndMSFT@gmail.com utente autenticato

Fare clic sul collegamento Gestisci . Nota i 0 accessi esterni (accessi social) associati a questo account.

Gestisci vista

Fare clic sul collegamento a un altro servizio di accesso e accettare le richieste dell'app. Nell'immagine seguente Facebook è il provider di autenticazione esterno:

Gestisci la visualizzazione degli accessi esterni che elenca Facebook

I due conti sono stati combinati. È possibile accedere con uno dei due account. Potresti voler consentire ai tuoi utenti di aggiungere account locali nel caso in cui il servizio di autenticazione tramite social login non sia disponibile o, più probabilmente, abbiano perso l'accesso al proprio account social.

Abilitare la conferma dell'account dopo che un sito ha utenti

L'abilitazione della conferma dell'account in un sito con gli utenti blocca tutti gli utenti esistenti. Gli utenti esistenti vengono bloccati perché gli account non vengono confermati. Per aggirare il blocco utente esistente, usare uno degli approcci seguenti:

  • Aggiornare il database per contrassegnare tutti gli utenti esistenti come confermati.
  • Confermare gli utenti esistenti. Ad esempio, inviare messaggi di posta elettronica in batch con collegamenti di conferma.