Поделиться через


Подтверждение учетной записи и восстановление паролей в ASP.NET Core Blazor

Примечание.

Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 9 этой статьи.

Внимание

Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

В текущем выпуске см . версию .NET 9 этой статьи.

В этой статье объясняется, как настроить ASP.NET Core Blazor Web App с подтверждением электронной почты и восстановлением паролей.

Примечание.

Эта статья относится только к Blazor Web Apps. Сведения о реализации подтверждения электронной почты и восстановления паролей для автономных Blazor WebAssembly приложений с ASP.NET Core Identityсм. в статье "Подтверждение учетной записи и восстановление паролей" в ASP.NET Core с ASP.NET CoreIdentityBlazor WebAssembly.

Пространство имен

Пространство имен приложения, используемое примером в этой статье BlazorSample. Обновите примеры кода, чтобы использовать пространство имен приложения.

Выбор и настройка поставщика электронной почты

В этой статье API транзакций Mailchimp используется через Mandrill.net для отправки электронной почты. Рекомендуется использовать службу электронной почты для отправки электронной почты, а не SMTP. SMTP сложно настроить и защитить должным образом. Независимо от используемой службы электронной почты, получить доступ к их рекомендациям для приложений .NET, создать учетную запись, настроить ключ API для своей службы и установить все необходимые пакеты NuGet.

Создайте класс для хранения ключа API поставщика секретной почты. В примере в этой статье используется класс с именем AuthMessageSenderOptions свойства EmailAuthKey для хранения ключа.

AuthMessageSenderOptions.cs:

namespace BlazorSample;

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

AuthMessageSenderOptions Зарегистрируйте экземпляр конфигурации в Program файле:

builder.Services.Configure<AuthMessageSenderOptions>(builder.Configuration);

Настройка секрета пользователя для ключа безопасности поставщика

Если проект уже инициализирован для средства Secret Manager, он уже будет иметь идентификатор секретов приложения (<AppSecretsId>) в файле проекта (.csproj). В Visual Studio можно определить, присутствует ли идентификатор секретов приложения, просмотрев панель свойств при выборе проекта в Обозреватель решений. Если приложение не было инициализировано, выполните следующую команду в командной оболочке, открытой в каталоге проекта. В Visual Studio можно использовать командную строку Разработчика PowerShell.

dotnet user-secrets init

Задайте ключ API с помощью средства диспетчера секретов. В следующем примере имя ключа соответствует EmailAuthKey AuthMessageSenderOptions.EmailAuthKey, а ключ представлен {KEY} заполнителем. Выполните следующую команду с помощью ключа API:

dotnet user-secrets set "EmailAuthKey" "{KEY}"

При использовании Visual Studio можно подтвердить, что секрет задан, щелкнув правой кнопкой мыши проект сервера в Обозреватель решений и выбрав "Управление секретами пользователей".

Дополнительные сведения см. в статье Надежное хранение секретов приложений при разработке в ASP.NET Core.

Предупреждение

Не сохраняйте секреты приложений, строка подключения, учетные данные, пароли, персональные идентификационные номера (ПИН-коды), частный код C#/.NET или закрытые ключи и токены в клиентском коде, который всегда небезопасн. В средах тестирования и промежуточной и рабочей среды код на стороне Blazor сервера и веб-API должны использовать безопасные потоки проверки подлинности, которые не поддерживают учетные данные в файлах кода проекта или конфигурации. Вне локального тестирования разработки рекомендуется избегать использования переменных среды для хранения конфиденциальных данных, так как переменные среды не являются наиболее безопасным подходом. Для локального тестирования разработки средство Secret Manager рекомендуется для защиты конфиденциальных данных. Дополнительные сведения см. в разделе "Безопасное обслуживание конфиденциальных данных и учетных данных".

Реализуйте IEmailSender

Следующий пример основан на API транзакций Mailchimp с помощью Mandrill.net. Сведения о том, как реализовать отправку сообщения электронной почты, см. в документации по другому поставщику.

Добавьте в проект пакет NuGet Mandrill.net.

Добавьте следующий EmailSender класс для реализации IEmailSender<TUser>. В следующем примере ApplicationUser используется .IdentityUser Разметка HTML сообщения может быть дополнительно настроена. Если переданный message MandrillMessage символ начинается с символа < , API Mandrill.net предполагает, что текст сообщения состоит в HTML.

Components/Account/EmailSender.cs:

using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Mandrill;
using Mandrill.Model;
using BlazorSample.Data;

namespace BlazorSample.Components.Account;

public class EmailSender(IOptions<AuthMessageSenderOptions> optionsAccessor,
    ILogger<EmailSender> logger) : IEmailSender<ApplicationUser>
{
    private readonly ILogger logger = logger;

    public AuthMessageSenderOptions Options { get; } = optionsAccessor.Value;

    public Task SendConfirmationLinkAsync(AppUser user, string email,
        string confirmationLink) => SendEmailAsync(email, "Confirm your email",
        "<html lang=\"en\"><head></head><body>Please confirm your account by " +
        $"<a href='{confirmationLink}'>clicking here</a>.</body></html>");

    public Task SendPasswordResetLinkAsync(AppUser user, string email,
        string resetLink) => SendEmailAsync(email, "Reset your password",
        "<html lang=\"en\"><head></head><body>Please reset your password by " +
        $"<a href='{resetLink}'>clicking here</a>.</body></html>");

    public Task SendPasswordResetCodeAsync(AppUser user, string email,
        string resetCode) => SendEmailAsync(email, "Reset your password",
        "<html lang=\"en\"><head></head><body>Please reset your password " +
        $"using the following code:<br>{resetCode}</body></html>");

    public async Task SendEmailAsync(string toEmail, string subject, string message)
    {
        if (string.IsNullOrEmpty(Options.EmailAuthKey))
        {
            throw new Exception("Null EmailAuthKey");
        }

        await Execute(Options.EmailAuthKey, subject, message, toEmail);
    }

    public async Task Execute(string apiKey, string subject, string message, 
        string toEmail)
    {
        var api = new MandrillApi(apiKey);
        var mandrillMessage = new MandrillMessage("sarah@contoso.com", toEmail, 
            subject, message);
        await api.Messages.SendAsync(mandrillMessage);

        logger.LogInformation("Email to {EmailAddress} sent!", toEmail);
    }
}

Примечание.

Содержимое текста для сообщений может потребовать специального кодирования для поставщика услуг электронной почты. Если ссылки в тексте сообщения не могут быть выполнены в сообщении электронной почты, обратитесь к документации поставщика услуг, чтобы устранить проблему.

Настройка приложения для поддержки электронной почты

Program В файле измените реализацию отправителя электронной почты на EmailSender:

- builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSender>();
+ builder.Services.AddSingleton<IEmailSender<ApplicationUser>, EmailSender>();

IdentityNoOpEmailSender Удалите (Components/Account/IdentityNoOpEmailSender.cs) из приложения.

В компоненте RegisterConfirmation (Components/Account/Pages/RegisterConfirmation.razor) удалите условный блок в блоке@code, который проверяет, является IdentityNoOpEmailSenderли EmailSender компонент:

- else if (EmailSender is IdentityNoOpEmailSender)
- {
-     ...
- }

Кроме того, в компоненте RegisterConfirmation удалите Razor разметку и код для проверки emailConfirmationLink поля, оставив только строку, в которую указывает пользователю проверить электронную почту ...

- @if (emailConfirmationLink is not null)
- {
-     ...
- }
- else
- {
     <p>Please check your email to confirm your account.</p>
- }

@code {
-    private string? emailConfirmationLink;

     ...
}

Включение подтверждения учетной записи после того, как сайт имеет пользователей

Включение подтверждения учетной записи на сайте с пользователями блокирует всех существующих пользователей. Существующие пользователи заблокированы, так как их учетные записи не подтверждены. Чтобы обойти существующую блокировку пользователей, используйте один из следующих подходов:

  • Обновите базу данных, чтобы пометить всех существующих пользователей как подтвержденную.
  • Подтвердите существующих пользователей. Например, пакетная отправка сообщений электронной почты с ссылками подтверждения.

Время ожидания электронной почты и действий

Время ожидания бездействия по умолчанию — 14 дней. Следующий код задает время ожидания бездействия в пять дней с скользящим сроком действия:

builder.Services.ConfigureApplicationCookie(options => {
    options.ExpireTimeSpan = TimeSpan.FromDays(5);
    options.SlidingExpiration = true;
});

Изменение всех ASP.NET срок действия маркера защиты данных Core

Следующий код изменяет период ожидания маркеров защиты данных на три часа:

builder.Services.Configure<DataProtectionTokenProviderOptions>(options =>
    options.TokenLifespan = TimeSpan.FromHours(3));

Встроенные Identity маркеры пользователей (AspNetCore/src/IdentityExtensions.Core/src/TokenOptions.cs) имеют однодневное время ожидания.

Примечание.

По ссылкам в документации на справочные материалы по .NET обычно загружается ветвь репозитория по умолчанию, которая представляет текущую разработку для следующего выпуска .NET. Чтобы выбрать тег для определенного выпуска, используйте раскрывающийся список Switch branches or tags (Переключение ветвей или тегов). Дополнительные сведения см. в статье Выбор тега версии исходного кода ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Изменение срока жизни маркера электронной почты

Срок действия маркера по умолчанию для маркеров Identity пользователя составляет один день.

Примечание.

По ссылкам в документации на справочные материалы по .NET обычно загружается ветвь репозитория по умолчанию, которая представляет текущую разработку для следующего выпуска .NET. Чтобы выбрать тег для определенного выпуска, используйте раскрывающийся список Switch branches or tags (Переключение ветвей или тегов). Дополнительные сведения см. в статье Выбор тега версии исходного кода ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Чтобы изменить срок жизни маркера электронной почты, добавьте настраиваемый DataProtectorTokenProvider<TUser> и DataProtectionTokenProviderOptions.

CustomTokenProvider.cs:

using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;

namespace BlazorSample;

public class CustomEmailConfirmationTokenProvider<TUser>
    : DataProtectorTokenProvider<TUser> where TUser : class
{
    public CustomEmailConfirmationTokenProvider(
        IDataProtectionProvider dataProtectionProvider,
        IOptions<EmailConfirmationTokenProviderOptions> options,
        ILogger<DataProtectorTokenProvider<TUser>> logger)
        : base(dataProtectionProvider, options, logger)
    {
    }
}

public class EmailConfirmationTokenProviderOptions 
    : DataProtectionTokenProviderOptions
{
    public EmailConfirmationTokenProviderOptions()
    {
        Name = "EmailDataProtectorTokenProvider";
        TokenLifespan = TimeSpan.FromHours(4);
    }
}

public class CustomPasswordResetTokenProvider<TUser> 
    : DataProtectorTokenProvider<TUser> where TUser : class
{
    public CustomPasswordResetTokenProvider(
        IDataProtectionProvider dataProtectionProvider,
        IOptions<PasswordResetTokenProviderOptions> options,
        ILogger<DataProtectorTokenProvider<TUser>> logger)
        : base(dataProtectionProvider, options, logger)
    {
    }
}

public class PasswordResetTokenProviderOptions : 
    DataProtectionTokenProviderOptions
{
    public PasswordResetTokenProviderOptions()
    {
        Name = "PasswordResetDataProtectorTokenProvider";
        TokenLifespan = TimeSpan.FromHours(3);
    }
}

Настройте службы для использования пользовательского поставщика маркеров в Program файле:

builder.Services.AddIdentityCore<ApplicationUser>(options =>
    {
        options.SignIn.RequireConfirmedAccount = true;
        options.Tokens.ProviderMap.Add("CustomEmailConfirmation",
            new TokenProviderDescriptor(
                typeof(CustomEmailConfirmationTokenProvider<ApplicationUser>)));
        options.Tokens.EmailConfirmationTokenProvider = 
            "CustomEmailConfirmation";
    })
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddSignInManager()
    .AddDefaultTokenProviders();

builder.Services
    .AddTransient<CustomEmailConfirmationTokenProvider<ApplicationUser>>();

Устранение неполадок

Если вы не можете получить электронную почту, выполните следующие действия:

  • Задайте точку останова для EmailSender.Execute проверки SendEmailAsync .
  • Создайте консольное приложение для отправки электронной почты с помощью кода, EmailSender.Execute аналогичного отладке проблемы.
  • Просмотрите страницы журнала электронной почты учетной записи на веб-сайте поставщика электронной почты.
  • Проверьте папку нежелательной почты для сообщений.
  • Попробуйте другой псевдоним электронной почты в другом поставщике электронной почты, например Microsoft, Yahoo или Gmail.
  • Попробуйте отправить в разные учетные записи электронной почты.

Дополнительные ресурсы