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. Questa esercitazione non è un argomento iniziale. È necessario avere familiarità con:

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 l'utente con conferma tramite posta elettronica simulata

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

  • Selezionare il collegamento Click here to confirm your account.
  • Selezionare il collegamento Account di accesso e accedere 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.

Il Click here to confirm your account collegamento viene visualizzato perché un IEmailSender non è stato implementato e registrato con il contenitore di inserimento delle dipendenze. Vedere l'origineRegisterConfirmation.

Nota

I collegamenti della documentazione all'origine del riferimento .NET in genere caricano il ramo predefinito del repository, che rappresenta lo sviluppo corrente per la versione successiva di .NET. Per selezionare un tag per una versione specifica, usare l'elenco 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 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 Services/AuthMessageSenderOptions.cs:

namespace WebPWrecover.Services;

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

Configurare i segreti utente di SendGrid

SendGridKey Impostare con lo strumento secret-manager. Ad esempio:

dotnet user-secrets set SendGridKey <key>

Successfully saved SendGridKey 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 usare altri provider di posta elettronica.

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'app per supportare la posta elettronica

Aggiungere il codice seguente al file Program.cs:

  • Aggiungere EmailSender come servizio temporaneo.
  • Registrare l'istanza di AuthMessageSenderOptions configurazione.
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 dell'account predefinita quando è stato eseguito lo scaffolding di Account.RegisterConfirmation

Questa sezione si applica solo quando Account.RegisterConfirmation viene eseguito lo scaffolding. Ignorare questa sezione se non è stato sottoposto a scaffolding Account.RegisterConfirmation.

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

Per richiedere un account confermato e impedire l'accesso immediato durante la registrazione, impostare DisplayConfirmAccountLink = false nel file con scaffolding /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs :

// 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 eseguito lo scaffolding. RegisterConfirmation non sottoposto a scaffolding rileva automaticamente quando un IEmailSender è stato 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

Selezionare il collegamento Invia di nuovo conferma tramite posta elettronica nella pagina Di accesso .

Modificare il timeout dell'attività e della posta elettronica

Il timeout di inattività predefinito è 14 giorni. Il codice seguente imposta il timeout di inattività su 5 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 di tutti i token di protezione dei dati a 3 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 AspNetCore/src//IdentityExtensions.Core/src/TokenOptions.cs )hanno un timeout di un giorno.

Modificare la durata del token di posta elettronica

La durata del token predefinita dei token utente è un giorno.Identity 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:

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 non è possibile ricevere messaggi di posta elettronica funzionanti:

  • Impostare un punto di interruzione in EmailSender.Execute per verificare SendGridClient.SendEmailAsync che 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.

Combinare account di accesso di social network e locali

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

È 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.

Web application: RickAndMSFT@gmail.com user authenticated

Fare clic sul collegamento Gestisci . Si notino i 0 account esterni (account di accesso di social networking) associati a questo account.

Manage view

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:

Manage your external logins view listing Facebook

I due conti sono stati combinati. È possibile accedere con uno dei due account. È possibile che gli utenti aggiungano account locali nel caso in cui il servizio di autenticazione dell'account di accesso social sia inattivo o che abbiano perso l'accesso al proprio account di social networking.

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.

Prerequisiti

.NET Core 3.0 SDK o versione successiva

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 a /Identity/Account/RegisterConfirmation che contiene un collegamento per simulare la conferma tramite posta elettronica:

  • Selezionare il collegamento Click here to confirm your account.
  • Selezionare il collegamento Account di accesso e accedere 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

SendGridKey Impostare 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 AuthMessageSenderOptions configurazione.
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

Seguire le istruzioni per Scaffolding e scaffoldingIdentityAccount\RegisterConfirmation.

Disabilitare la verifica dell'account predefinita quando è stato eseguito lo scaffolding di Account.RegisterConfirmation

Questa sezione si applica solo quando Account.RegisterConfirmation viene eseguito lo scaffolding. Ignorare questa sezione se non è stato sottoposto a scaffolding Account.RegisterConfirmation.

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

Per richiedere un account confermato e impedire l'accesso immediato durante la registrazione, impostare DisplayConfirmAccountLink = false nel file con scaffolding /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs :

// 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 eseguito lo scaffolding. RegisterConfirmation non sottoposto a scaffolding rileva automaticamente quando un IEmailSender è stato 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 ASP.NET Core 5.0 e versioni successive selezionare il collegamento Invia di nuovo conferma tramite posta elettronica nella pagina Account di accesso .

Modificare il timeout dell'attività e della posta elettronica

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 del token predefinita dei token utente è un giorno.Identity 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:

  • Impostare un punto di interruzione in EmailSender.Execute per verificare SendGridClient.SendEmailAsync che 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.

Combinare account di accesso di social network e locali

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

È 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.

Web application: RickAndMSFT@gmail.com user authenticated

Fare clic sul collegamento Gestisci . Si notino i 0 account esterni (account di accesso di social networking) associati a questo account.

Manage view

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:

Manage your external logins view listing Facebook

I due conti sono stati combinati. È possibile accedere con uno dei due account. È possibile che gli utenti aggiungano account locali nel caso in cui il servizio di autenticazione dell'account di accesso social sia inattivo o che abbiano perso l'accesso al proprio account di social networking.

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.