Account confirmation and password recovery in ASP.NET Core (Confirmation de compte et récupération de mot de passe dans ASP.NET Core)

Par Rick Anderson, Ponant et Joe Audette

Ce tutoriel montre comment créer une application ASP.NET Core avec confirmation par e-mail et réinitialisation de mot de passe. Ce tutoriel n’est pas une rubrique de démarrage. Vous devez être familiarisé avec :

Prérequis

Créer et tester une application web avec authentification

Exécutez les commandes suivantes pour créer une application web avec authentification.

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

Inscrire un utilisateur avec confirmation par e-mail simulée

Exécutez l’application, sélectionnez le lien Inscrire et inscrivez un utilisateur. Une fois inscrit, vous êtes redirigé vers la page /Identity/Account/RegisterConfirmation qui contient un lien pour simuler la confirmation par e-mail :

  • Sélectionnez le lien Click here to confirm your account.
  • Sélectionnez le lien Connexion et connectez-vous avec les mêmes informations d’identification.
  • Sélectionnez le lien Hello YourEmail@provider.com! qui redirige vers la page /Identity/Account/Manage/PersonalData.
  • Sélectionnez l’onglet Données personnelles sur la gauche, puis sélectionnez Supprimer.

Le lien Click here to confirm your account s’affiche, car un IEmailSender n’a pas été implémenté ni inscrit auprès du conteneur d’injection de dépendances. Consultez la RegisterConfirmation source.

Notes

Les liens de documentation vers la source de référence .NET chargent généralement la branche par défaut du référentiel, qui représente le développement actuel pour la prochaine version de .NET. Pour sélectionner une balise pour une version spécifique, utilisez la liste déroulante Échanger les branches ou les balises. Pour plus d’informations, consultez Comment sélectionner une balise de version du code source ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Configurer un fournisseur de messagerie électronique

Dans ce tutoriel, SendGrid est utilisé pour envoyer des e-mails. Un compte et une clé SendGrid sont nécessaires pour envoyer des e-mails. Nous vous recommandons d’utiliser SendGrid ou un autre service de messagerie pour envoyer des e-mails plutôt que SMTP. SMTP est difficile à sécuriser et à configurer correctement.

Le compte SendGrid peut nécessiter l’ajout d’un expéditeur.

Créez une classe pour récupérer (fetch) la clé de messagerie sécurisée. Pour cet exemple, créez Services/AuthMessageSenderOptions.cs:

namespace WebPWrecover.Services;

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

Configurer les secrets utilisateur SendGrid

Définissez SendGridKey avec l’outil secret-manager. Par exemple :

dotnet user-secrets set SendGridKey <key>

Successfully saved SendGridKey to the secret store.

Sur Windows, Secret Manager stocke les paires clés/valeur dans un fichier secrets.json du %APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId> répertoire .

Le contenu du fichier secrets.json n’est pas chiffré. Le balisage suivant montre le fichier secrets.json. La valeur SendGridKey a été supprimée.

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

Pour plus d’informations, consultez Modèle d’options et Configuration.

Installer SendGrid

Ce tutoriel montre comment ajouter des notifications par e-mail via SendGrid, mais d’autres fournisseurs de messagerie peuvent être utilisés.

Installez le package NuGet SendGrid :

Depuis la Console du gestionnaire de package, saisissez la commande suivante :

Install-Package SendGrid

Consultez Prise en main gratuite de SendGrid pour vous inscrire à un compte SendGrid gratuit.

Implémenter IEmailSender

Pour implémenter IEmailSender, créez Services/EmailSender.cs avec un code similaire à ce qui suit :

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

Configurer l’application pour prendre en charge les e-mails

Ajoutez le code suivant au fichier Program.cs :

  • Ajouter EmailSender en tant que service temporaire.
  • Enregistrer l’instance de configuration 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();

Désactiver la vérification du compte par défaut lorsque Account.RegisterConfirmation a été généré automatiquement

Cette section s’applique uniquement lorsque Account.RegisterConfirmation est généré automatiquement. Ignorez cette section si vous n’avez pas généré Account.RegisterConfirmation automatiquement.

L’utilisateur est redirigé vers le Account.RegisterConfirmation où il peut sélectionner un lien pour que le compte soit confirmé. La valeur par défaut Account.RegisterConfirmation est utilisée uniquement pour les tests. La vérification automatique du compte doit être désactivée dans une application de production.

Pour exiger un compte confirmé et empêcher la connexion immédiate lors de l’inscription, définissez DisplayConfirmAccountLink = false dans le fichier généré automatiquement /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();
        }
    }
}

Cette étape n’est nécessaire que lorsque Account.RegisterConfirmation est généré automatiquement. La RegisterConfirmation non générée automatiquement détecte quand un IEmailSender a été implémenté et inscrit auprès du conteneur d’injection de dépendances.

S’inscrire, confirmer l’e-mail et réinitialiser le mot de passe

Exécutez l’application web et testez la confirmation du compte et le flux de récupération de mot de passe.

  • Exécutez l’application et inscrivez un nouvel utilisateur
  • Consultez votre boîte de réception pour obtenir le lien de confirmation de compte. Consultez Déboguer l’e-mail si vous ne recevez pas l’e-mail.
  • Cliquez sur le lien pour confirmer votre e-mail.
  • Se connecter avec votre e-mail et votre mot de passe.
  • Déconnectez-vous.

Tester la réinitialisation du mot de passe

  • Si vous êtes connecté, sélectionnez Se déconnecter.
  • Sélectionnez le lien Se connecter et sélectionnez le lien Vous avez oublié votre mot de passe ?.
  • Saisissez l’e-mail que vous avez utilisé pour créer le compte.
  • Un e-mail contenant un lien pour réinitialiser votre mot de passe est envoyé. Vérifiez vos e-mails et cliquez sur le lien pour réinitialiser votre mot de passe. Une fois votre mot de passe correctement réinitialisé, vous pouvez vous connecter avec votre e-mail et votre nouveau mot de passe.

Renvoyer l’e-mail de confirmation

Sélectionnez le lien Renvoyer l’e-mail de confirmation dans la page Connexion .

Modifier l’e-mail et le délai d’expiration d’activité

Le délai d'inactivité par défaut est de 14 jours. Le code suivant définit le délai d’inactivité à 5 jours :

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

Modifier les durées de vie de tous les jetons de protection des données

Le code suivant modifie la période de délai d’expiration de tous les jetons de protection des données à 3 heures :

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.

Les jetons utilisateur intégrés Identity (voir AspNetCore/src/Identity/Extensions.Core/src/TokenOptions.cs) ont un délai d’expiration d’un jour.

Modifier la durée de vie du jeton d’e-mail

La durée de vie par défaut des Identityjetons utilisateur est d’un jour. Cette section montre comment modifier la durée de vie du jeton d’e-mail.

Ajouter un DataProtectorTokenProvider<TUser> et un DataProtectionTokenProviderOptions personnalisés :

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

Ajoutez le fournisseur personnalisé au conteneur de service :

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.

Déboguer un e-mail

Si vous ne parvenez pas à faire fonctionner les e-mails :

  • Définissez un point d’arrêt dans EmailSender.Execute pour vérifier que SendGridClient.SendEmailAsync est appelé.
  • Créez une application console pour envoyer des e-mails à l’aide d’un code similaire à EmailSender.Execute.
  • Examinez la page Activité e-mail.
  • Vérifiez votre dossier de courrier indésirable.
  • Essayez un autre alias de messagerie sur un autre fournisseur de messagerie (Microsoft, Yahoo, Gmail, etc.)
  • Essayez de faire un envoi à d’autres comptes de messagerie.

Une bonne pratique de sécurité consiste à ne pas utiliser de secrets de production dans les tests et le développement. Si vous publiez l’application sur Azure, définissez les secrets SendGrid comme paramètres d’application dans le portail Azure Web App. Le système de configuration est configuré pour lire les clés des variables d’environnement.

Combiner les comptes de connexion sociale et locale

Pour terminer cette section, vous devez d’abord activer un fournisseur d’authentification externe. Consultez Authentification avec Facebook, Google et autres fournisseurs externes.

Vous pouvez combiner des comptes locaux et sociaux en cliquant sur le lien dans votre e-mail. Dans la séquence suivante, « RickAndMSFT@gmail.com » est d’abord créé en tant que connexion locale. Toutefois, vous pouvez d’abord créer le compte en tant que connexion sociale, puis ajouter une connexion locale.

Web application: RickAndMSFT@gmail.com user authenticated

Cliquez sur le lien Gérer. Notez le 0 externe (connexions sociales) associé à ce compte.

Manage view

Cliquez sur le lien vers un autre service de connexion et acceptez les demandes de l’application. Dans l’image suivante, Facebook est le fournisseur d’authentification externe :

Manage your external logins view listing Facebook

Les deux comptes ont été combinés. Vous pouvez vous connecter avec l’un ou l’autre compte. Vous pouvez souhaiter que vos utilisateurs ajoutent des comptes locaux au cas où leur service d’authentification de connexion sociale soit en panne ou, plus probablement, qu’ils ont perdu l’accès à leur compte de réseau social.

Activer la confirmation de compte après qu’un site a des utilisateurs

L’activation de la confirmation de compte sur un site avec des utilisateurs bloque tous les utilisateurs existants. Les utilisateurs existants sont bloqués, car leurs comptes ne sont pas confirmés. Pour contourner un blocage utilisateur existant, utilisez l’une des approches suivantes :

  • Mettez à jour la base de données pour marquer tous les utilisateurs existants comme étant confirmés.
  • Confirmer les utilisateurs existants. Par exemple, envoyez des e-mails par lots avec des liens de confirmation.

Prérequis

SDK .NET Core 3.0 ou version ultérieure

Créer et tester une application web avec authentification

Exécutez les commandes suivantes pour créer une application web avec authentification.

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

Exécutez l’application, sélectionnez le lien Inscrire et inscrivez un utilisateur. Une fois inscrit, vous êtes redirigé vers la page /Identity/Account/RegisterConfirmation qui contient un lien pour simuler la confirmation par e-mail :

  • Sélectionnez le lien Click here to confirm your account.
  • Sélectionnez le lien Connexion et connectez-vous avec les mêmes informations d’identification.
  • Sélectionnez le lien Hello YourEmail@provider.com!, qui vous redirige vers la page /Identity/Account/Manage/PersonalData.
  • Sélectionnez l’onglet Données personnelles sur la gauche, puis sélectionnez Supprimer.

Configurer un fournisseur de messagerie électronique

Dans ce tutoriel, SendGrid est utilisé pour envoyer des e-mails. Vous pouvez utiliser d’autres fournisseurs de messagerie. Nous vous recommandons d’utiliser SendGrid ou un autre service de messagerie pour envoyer des e-mails. SMTP est difficile à configurer, de sorte que le courrier n’est pas marqué comme courrier indésirable.

Le compte SendGrid peut nécessiter l’ajout d’un expéditeur.

Créez une classe pour récupérer (fetch) la clé de messagerie sécurisée. Pour cet exemple, créez Services/AuthMessageSenderOptions.cs:

namespace WebPWrecover.Services;

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

Configurer les secrets utilisateur SendGrid

Définissez SendGridKey avec l’outil secret-manager. Par exemple :

dotnet user-secrets set SendGridKey <SG.key>

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

Sur Windows, Secret Manager stocke les paires clés/valeur dans un fichier secrets.json du %APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId> répertoire .

Le contenu du fichier secrets.json n’est pas chiffré. Le balisage suivant montre le fichier secrets.json. La valeur SendGridKey a été supprimée.

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

Pour plus d’informations, consultez Modèle d’options et Configuration.

Installer SendGrid

Ce tutoriel montre comment ajouter des Notifications par e-mail via SendGrid, mais vous pouvez envoyer des e-mails en utilisant SMTP et d’autres systèmes.

Installez le package NuGet SendGrid :

Depuis la Console du gestionnaire de package, saisissez la commande suivante :

Install-Package SendGrid

Consultez Prise en main gratuite de SendGrid pour vous inscrire à un compte SendGrid gratuit.

Implémenter IEmailSender

Pour implémenter IEmailSender, créez Services/EmailSender.cs avec un code similaire à ce qui suit :

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

Configurer le démarrage pour prendre en charge les e-mails

Ajoutez le code suivant à la méthode ConfigureServices dans le fichier Startup.cs :

  • Ajouter EmailSender en tant que service temporaire.
  • Enregistrer l’instance de configuration 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();

Générer automatiquement RegisterConfirmation

Suivez les instructions de Générer automatiquement Identity et générez Account\RegisterConfirmation.

Désactiver la vérification du compte par défaut lorsque Account.RegisterConfirmation a été généré automatiquement

Cette section s’applique uniquement lorsque Account.RegisterConfirmation est généré automatiquement. Ignorez cette section si vous n’avez pas généré Account.RegisterConfirmation automatiquement.

L’utilisateur est redirigé vers le Account.RegisterConfirmation où il peut sélectionner un lien pour que le compte soit confirmé. La valeur par défaut Account.RegisterConfirmation est utilisée uniquement pour les tests. La vérification automatique du compte doit être désactivée dans une application de production.

Pour exiger un compte confirmé et empêcher la connexion immédiate lors de l’inscription, définissez DisplayConfirmAccountLink = false dans le fichier généré automatiquement /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();
        }
    }
}

Cette étape n’est nécessaire que lorsque Account.RegisterConfirmation est généré automatiquement. La RegisterConfirmation non générée automatiquement détecte quand un IEmailSender a été implémenté et inscrit auprès du conteneur d’injection de dépendances.

S’inscrire, confirmer l’e-mail et réinitialiser le mot de passe

Exécutez l’application web et testez la confirmation du compte et le flux de récupération de mot de passe.

  • Exécutez l’application et inscrivez un nouvel utilisateur
  • Consultez votre boîte de réception pour obtenir le lien de confirmation de compte. Consultez Déboguer l’e-mail si vous ne recevez pas l’e-mail.
  • Cliquez sur le lien pour confirmer votre e-mail.
  • Se connecter avec votre e-mail et votre mot de passe.
  • Déconnectez-vous.

Tester la réinitialisation du mot de passe

  • Si vous êtes connecté, sélectionnez Se déconnecter.
  • Sélectionnez le lien Se connecter et sélectionnez le lien Vous avez oublié votre mot de passe ?.
  • Saisissez l’e-mail que vous avez utilisé pour créer le compte.
  • Un e-mail contenant un lien pour réinitialiser votre mot de passe est envoyé. Vérifiez vos e-mails et cliquez sur le lien pour réinitialiser votre mot de passe. Une fois votre mot de passe correctement réinitialisé, vous pouvez vous connecter avec votre e-mail et votre nouveau mot de passe.

Renvoyer l’e-mail de confirmation

Dans ASP.NET Core 5.0 et versions ultérieures, sélectionnez le lien Renvoyer l’e-mail de confirmation sur la page Connexion.

Modifier l’e-mail et le délai d’expiration d’activité

Le délai d'inactivité par défaut est de 14 jours. Le code suivant définit le délai d’inactivité à 5 jours :

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

Modifier les durées de vie de tous les jetons de protection des données

Le code suivant modifie la période de délai d’expiration de tous les jetons de protection des données à 3 heures :

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

Les jetons utilisateur intégrés Identity (voir AspNetCore/src/Identity/Extensions.Core/src/TokenOptions.cs) ont un délai d’expiration d’un jour.

Modifier la durée de vie du jeton d’e-mail

La durée de vie par défaut des Identityjetons utilisateur est d’un jour. Cette section montre comment modifier la durée de vie du jeton d’e-mail.

Ajouter un DataProtectorTokenProvider<TUser> et un DataProtectionTokenProviderOptions personnalisés :

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

Ajoutez le fournisseur personnalisé au conteneur de service :

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

Déboguer un e-mail

Si vous ne parvenez pas à faire fonctionner les e-mails :

  • Définissez un point d’arrêt dans EmailSender.Execute pour vérifier que SendGridClient.SendEmailAsync est appelé.
  • Créez une application console pour envoyer des e-mails à l’aide d’un code similaire à EmailSender.Execute.
  • Examinez la page Activité e-mail.
  • Vérifiez votre dossier de courrier indésirable.
  • Essayez un autre alias de messagerie sur un autre fournisseur de messagerie (Microsoft, Yahoo, Gmail, etc.)
  • Essayez de faire un envoi à d’autres comptes de messagerie.

Une bonne pratique de sécurité consiste à ne pas utiliser de secrets de production dans les tests et le développement. Si vous publiez l’application sur Azure, définissez les secrets SendGrid comme paramètres d’application dans le portail Azure Web App. Le système de configuration est configuré pour lire les clés des variables d’environnement.

Combiner les comptes de connexion sociale et locale

Pour terminer cette section, vous devez d’abord activer un fournisseur d’authentification externe. Consultez Authentification avec Facebook, Google et autres fournisseurs externes.

Vous pouvez combiner des comptes locaux et sociaux en cliquant sur le lien dans votre e-mail. Dans la séquence suivante, « RickAndMSFT@gmail.com » est d’abord créé en tant que connexion locale. Toutefois, vous pouvez d’abord créer le compte en tant que connexion sociale, puis ajouter une connexion locale.

Web application: RickAndMSFT@gmail.com user authenticated

Cliquez sur le lien Gérer. Notez le 0 externe (connexions sociales) associé à ce compte.

Manage view

Cliquez sur le lien vers un autre service de connexion et acceptez les demandes de l’application. Dans l’image suivante, Facebook est le fournisseur d’authentification externe :

Manage your external logins view listing Facebook

Les deux comptes ont été combinés. Vous pouvez vous connecter avec l’un ou l’autre compte. Vous pouvez souhaiter que vos utilisateurs ajoutent des comptes locaux au cas où leur service d’authentification de connexion sociale soit en panne ou, plus probablement, qu’ils ont perdu l’accès à leur compte de réseau social.

Activer la confirmation de compte après qu’un site a des utilisateurs

L’activation de la confirmation de compte sur un site avec des utilisateurs bloque tous les utilisateurs existants. Les utilisateurs existants sont bloqués, car leurs comptes ne sont pas confirmés. Pour contourner un blocage utilisateur existant, utilisez l’une des approches suivantes :

  • Mettez à jour la base de données pour marquer tous les utilisateurs existants comme étant confirmés.
  • Confirmer les utilisateurs existants. Par exemple, envoyez des e-mails par lots avec des liens de confirmation.