ASP.NET Core'da hesap onayı ve parola kurtarma

Rick Anderson, Ponant ve Joe Audette tarafından

Bu öğreticide, e-posta onayı ve parola sıfırlama ile bir ASP.NET Core uygulaması oluşturma işlemi gösterilmektedir. Bu öğretici başlangıç konusu değildir . Aşağıdakiler hakkında bilgi sahibi olmanız gerekir:

Bu makaledeki yönergeleri ekleyen veya yerine geçen yönergeler için Blazor bkz . ASP.NET Core'da Blazorhesap onayı ve parola kurtarma.

Önkoşullar

Kimlik doğrulaması ile web uygulaması oluşturma ve test edin

Kimlik doğrulamasıyla bir web uygulaması oluşturmak için aşağıdaki komutları çalıştırın.

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

Kullanıcıyı sanal e-posta onayıyla kaydetme

Uygulamayı çalıştırın, Kaydet bağlantısını seçin ve bir kullanıcı kaydedin. Kaydolduktan sonra, e-posta onayını /Identity/Account/RegisterConfirmation simüle etmek için bir bağlantı içeren sayfaya yönlendirilirsiniz:

  • Click here to confirm your account bağlantısını seçin.
  • Oturum aç bağlantısını seçin ve aynı kimlik bilgileriyle oturum açın.
  • Sayfaya Hello YourEmail@provider.com! yönlendiren /Identity/Account/Manage/PersonalData bağlantıyı seçin.
  • Soldaki Kişisel veriler sekmesini ve ardından Sil'i seçin.

IEmailSender Click here to confirm your account uygulanmadığından ve bağımlılık ekleme kapsayıcısıyla kaydedilmediğinden bağlantı görüntülenir. RegisterConfirmation Kaynağa bakın.

Not

.NET başvuru kaynağına yönelik belge bağlantıları genellikle deponun varsayılan dalını yükler ve bu dal .NET'in sonraki sürümü için geçerli geliştirmeyi temsil eder. Belirli bir sürümün etiketini seçmek için Dalları veya etiketleri değiştir açılan listesini kullanın. Daha fazla bilgi için bkz. ASP.NET Core kaynak kodunun sürüm etiketini seçme (dotnet/AspNetCore.Docs #26205).

E-posta sağlayıcısı yapılandırma

Bu öğreticide, e-posta göndermek için SendGrid kullanılır. E-posta göndermek için bir SendGrid hesabı ve anahtarı gerekir. SMTP yerine e-posta göndermek için SendGrid veya başka bir e-posta hizmeti kullanmanızı öneririz. SMTP'nin güvenliğini sağlamak ve doğru şekilde ayarlamak zordur.

SendGrid hesabı bir Gönderen eklenmesini gerektirebilir.

Güvenli e-posta anahtarını getirmek için bir sınıf oluşturun. Bu örnek için oluşturun Services/AuthMessageSenderOptions.cs:

namespace WebPWrecover.Services;

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

SendGrid kullanıcı gizli dizilerini yapılandırma

SendGridKey gizli dizi yöneticisi aracıyla öğesini ayarlayın. Örneğin:

dotnet user-secrets set SendGridKey <key>

Successfully saved SendGridKey to the secret store.

Windows'da, Gizli Dizi Yöneticisi anahtarları/değer çiftlerini dizindeki bir secrets.json dosyada %APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId> depolar.

Dosyanın içeriği secrets.json şifrelenmez. Aşağıdaki işaretlemede dosya gösterilmektedir secrets.json . Değer SendGridKey kaldırıldı.

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

Daha fazla bilgi için bkz . Seçenekler düzeni ve yapılandırması.

SendGrid'i yükleme

Bu öğreticide SendGrid aracılığıyla e-posta bildirimlerinin nasıl ekleneceği gösterilmektedir, ancak diğer e-posta sağlayıcıları kullanılabilir.

SendGrid NuGet paketini yükleyin:

Paket Yöneticisi Konsolu'ndan aşağıdaki komutu girin:

Install-Package SendGrid

Ücretsiz bir SendGrid hesabına kaydolmak için bkz . SendGrid'i Ücretsiz Kullanmaya Başlama.

IEmailSender Uygulama

uygulamak IEmailSenderiçin aşağıdakine benzer bir kodla oluşturun Services/EmailSender.cs :

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

Uygulamayı e-postayı destekleyecek şekilde yapılandırma

Program.cs dosyasına aşağıdaki kodu ekleyin:

  • Geçici hizmet olarak ekleyin EmailSender .
  • Yapılandırma örneğini AuthMessageSenderOptions kaydedin.
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();

Account.RegisterConfirmation iskelesi yapıldığında varsayılan hesap doğrulamayı devre dışı bırakma

Bu bölüm yalnızca yapı iskelesi yapıldığında Account.RegisterConfirmation geçerlidir. yapı iskelesi Account.RegisterConfirmationkurmadıysanız bu bölümü atlayın.

Kullanıcı, hesabın Account.RegisterConfirmation onaylanması için bir bağlantı seçebileceği konuma yönlendirilir. Varsayılan değer Account.RegisterConfirmation yalnızca test için kullanılır, üretim uygulamasında otomatik hesap doğrulaması devre dışı bırakılmalıdır.

Onaylanan bir hesap gerektirmek ve kayıt sırasında hemen oturum açmayı önlemek için, iskeledeki /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs dosyada ayarlayınDisplayConfirmAccountLink = false:

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable

using System;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.WebUtilities;

namespace WebPWrecover.Areas.Identity.Pages.Account
{
    [AllowAnonymous]
    public class RegisterConfirmationModel : PageModel
    {
        private readonly UserManager<IdentityUser> _userManager;
        private readonly IEmailSender _sender;

        public RegisterConfirmationModel(UserManager<IdentityUser> userManager, IEmailSender sender)
        {
            _userManager = userManager;
            _sender = sender;
        }

        /// <summary>
        ///     This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
        ///     directly from your code. This API may change or be removed in future releases.
        /// </summary>
        public string Email { get; set; }

        /// <summary>
        ///     This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
        ///     directly from your code. This API may change or be removed in future releases.
        /// </summary>
        public bool DisplayConfirmAccountLink { get; set; }

        /// <summary>
        ///     This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
        ///     directly from your code. This API may change or be removed in future releases.
        /// </summary>
        public string EmailConfirmationUrl { get; set; }

        public async Task<IActionResult> OnGetAsync(string email, string returnUrl = null)
        {
            if (email == null)
            {
                return RedirectToPage("/Index");
            }
            returnUrl = returnUrl ?? Url.Content("~/");

            var user = await _userManager.FindByEmailAsync(email);
            if (user == null)
            {
                return NotFound($"Unable to load user with email '{email}'.");
            }

            Email = email;
            // Once you add a real email sender, you should remove this code that lets you confirm the account
            DisplayConfirmAccountLink = false;
            if (DisplayConfirmAccountLink)
            {
                var userId = await _userManager.GetUserIdAsync(user);
                var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
                EmailConfirmationUrl = Url.Page(
                    "/Account/ConfirmEmail",
                    pageHandler: null,
                    values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
                    protocol: Request.Scheme);
            }

            return Page();
        }
    }
}

Bu adım yalnızca yapı iskelesi yapıldığında Account.RegisterConfirmation gereklidir. İskeleli olmayan RegisterConfirmation, bir IEmailSender'ın ne zaman uygulandığını ve bağımlılık ekleme kapsayıcısıyla ne zaman kaydedildiğini otomatik olarak algılar.

E-postayı kaydetme, onaylama ve parolayı sıfırlama

Web uygulamasını çalıştırın ve hesap onayını ve parola kurtarma akışını test edin.

  • Uygulamayı çalıştırma ve yeni bir kullanıcı kaydetme
  • Hesap onay bağlantısı için e-postanızı kontrol edin. E-postayı alamıyorsanız bkz. E-postada hata ayıklama.
  • E-postanızı onaylamak için bağlantıya tıklayın.
  • E-postanız ve parolanızla oturum açın.
  • Oturumu kapatma.

Parola sıfırlamayı test et

  • Oturum açtıysanız Oturumu Kapat'ı seçin.
  • Oturum aç bağlantısını seçin ve Parolanızı mı unuttunuz? bağlantısını seçin.
  • Hesabı kaydetmek için kullandığınız e-postayı girin.
  • Parolanızı sıfırlama bağlantısını içeren bir e-posta gönderilir. E-postanızı kontrol edin ve parolanızı sıfırlamak için bağlantıya tıklayın. Parolanız başarıyla sıfırlandıktan sonra e-postanız ve yeni parolanızla oturum açabilirsiniz.

E-posta onaylarını yeniden gönderme

Oturum açma sayfasında E-postayı yeniden gönder onay bağlantısını seçin.

E-posta ve etkinlik zaman aşımını değiştirme

Varsayılan etkinlik dışı zaman aşımı 14 gündür. Aşağıdaki kod etkinlik dışı zaman aşımını 5 güne ayarlar:

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

Tüm veri koruma belirteci kullanım ömrünü değiştirme

Aşağıdaki kod tüm veri koruma belirteçleri zaman aşımı süresini 3 saat olarak değiştirir:

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.

Yerleşik Identity kullanıcı belirteçlerinin (bkz . AspNetCore/src//IdentityExtensions.Core/src/TokenOptions.cs )bir günlük zaman aşımı vardır.

E-posta belirteci kullanım ömrünü değiştirme

Kullanıcı belirteçlerinin Identity varsayılan belirteç ömrü bir gündür. Bu bölümde e-posta belirteci kullanım ömrünün nasıl değiştireceği gösterilmektedir.

Özel DataProtectorTokenProvider<TUser> ve DataProtectionTokenProviderOptionsekleyin:

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

Özel sağlayıcıyı hizmet kapsayıcısına ekleyin:

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.

E-posta hatalarını ayıklama

E-postayı çalıştıramıyorsanız:

  • çağrıldığını doğrulamak SendGridClient.SendEmailAsync için içinde EmailSender.Execute bir kesme noktası ayarlayın.
  • ile benzer bir kod kullanarak e-posta göndermek için EmailSender.Executebir konsol uygulaması oluşturun.
  • E-posta Etkinliği sayfasını gözden geçirin.
  • İstenmeyen posta klasörünüzü denetleyin.
  • Farklı bir e-posta sağlayıcısında (Microsoft, Yahoo, Gmail vb.) başka bir e-posta diğer adı deneyin
  • Farklı e-posta hesaplarına göndermeyi deneyin.

Güvenlik açısından en iyi yöntem, test ve geliştirme aşamasında üretim gizli dizilerini kullanmamaktır. Uygulamayı Azure'da yayımlarsanız, Azure Web App portalında SendGrid gizli dizilerini uygulama ayarları olarak ayarlayın. Yapılandırma sistemi, ortam değişkenlerinden anahtarları okuyacak şekilde ayarlanır.

Sosyal ve yerel oturum açma hesaplarını birleştirme

Bu bölümü tamamlamak için önce bir dış kimlik doğrulama sağlayıcısını etkinleştirmeniz gerekir. Bkz . Facebook, Google ve dış sağlayıcı kimlik doğrulaması.

E-posta bağlantınıza tıklayarak yerel ve sosyal hesapları birleştirebilirsiniz. Aşağıdaki sırayla, "RickAndMSFT@gmail.com" ilk olarak yerel oturum açma olarak oluşturulur; ancak hesabı önce sosyal oturum açma olarak oluşturabilir, ardından yerel oturum açma bilgisi ekleyebilirsiniz.

Web uygulaması: RickAndMSFT@gmail.com kullanıcının kimliği doğrulandı

Yönet bağlantısına tıklayın. Bu hesapla ilişkilendirilmiş 0 harici (sosyal oturum açma bilgileri) not edin.

Görünümü yönet

Başka bir oturum açma hizmetinin bağlantısına tıklayın ve uygulama isteklerini kabul edin. Aşağıdaki görüntüde, Facebook dış kimlik doğrulama sağlayıcısıdır:

Facebook'un listelendiği dış oturum açma bilgilerinizi yönetme

İki hesap birleştirildi. İki hesapla da oturum açabilirsiniz. Kullanıcılarınızın sosyal oturum açma kimlik doğrulama hizmetinin çalışmamış olması veya sosyal hesaplarına erişimi kaybetme olasılığı daha yüksek olması durumunda yerel hesaplar eklemesini isteyebilirsiniz.

Bir sitede kullanıcılar olduktan sonra hesap onaylarını etkinleştirme

Kullanıcıların olduğu bir sitede hesap onayını etkinleştirmek, mevcut tüm kullanıcıları kilitler. Hesapları onaylanmamış olduğundan mevcut kullanıcılar kilitlenir. Mevcut kullanıcı kilitlenmesine geçici bir çözüm bulmak için aşağıdaki yaklaşımlardan birini kullanın:

  • Veritabanını, var olan tüm kullanıcıları onaylandı olarak işaretlemek için güncelleştirin.
  • Mevcut kullanıcıları onaylayın. Örneğin, onay bağlantıları içeren toplu gönderme e-postaları.

Önkoşullar

.NET Core 3.0 SDK veya üzeri

Kimlik doğrulaması ile web uygulaması oluşturma ve test edin

Kimlik doğrulamasıyla bir web uygulaması oluşturmak için aşağıdaki komutları çalıştırın.

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

Uygulamayı çalıştırın, Kaydet bağlantısını seçin ve bir kullanıcı kaydedin. Kaydolduktan sonra, e-posta onayını /Identity/Account/RegisterConfirmation simüle etmek için bir bağlantı içeren sayfaya yönlendirilirsiniz:

  • Click here to confirm your account bağlantısını seçin.
  • Oturum aç bağlantısını seçin ve aynı kimlik bilgileriyle oturum açın.
  • Sizi /Identity/Account/Manage/PersonalData sayfaya Hello YourEmail@provider.com! yönlendiren bağlantıyı seçin.
  • Soldaki Kişisel veriler sekmesini ve ardından Sil'i seçin.

E-posta sağlayıcısı yapılandırma

Bu öğreticide, e-posta göndermek için SendGrid kullanılır. Diğer e-posta sağlayıcılarını kullanabilirsiniz. E-posta göndermek için SendGrid veya başka bir e-posta hizmeti kullanmanızı öneririz. SMTP'nin yapılandırılması zordur, bu nedenle posta istenmeyen posta olarak işaretlenmez.

SendGrid hesabı bir Gönderen eklenmesini gerektirebilir.

Güvenli e-posta anahtarını getirmek için bir sınıf oluşturun. Bu örnek için oluşturun Services/AuthMessageSenderOptions.cs:

namespace WebPWrecover.Services;

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

SendGrid kullanıcı gizli dizilerini yapılandırma

SendGridKey gizli dizi yöneticisi aracıyla öğesini ayarlayın. Örneğin:

dotnet user-secrets set SendGridKey <SG.key>

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

Windows'da, Gizli Dizi Yöneticisi anahtarları/değer çiftlerini dizindeki bir secrets.json dosyada %APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId> depolar.

Dosyanın içeriği secrets.json şifrelenmez. Aşağıdaki işaretlemede dosya gösterilmektedir secrets.json . Değer SendGridKey kaldırıldı.

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

Daha fazla bilgi için bkz . Seçenekler düzeni ve yapılandırması.

SendGrid'i yükleme

Bu öğreticide SendGrid aracılığıyla e-posta bildirimlerinin nasıl ekleneceği gösterilmektedir, ancak SMTP ve diğer mekanizmaları kullanarak e-posta gönderebilirsiniz.

SendGrid NuGet paketini yükleyin:

Paket Yöneticisi Konsolu'ndan aşağıdaki komutu girin:

Install-Package SendGrid

Ücretsiz bir SendGrid hesabına kaydolmak için bkz . SendGrid'i Ücretsiz Kullanmaya Başlama.

IEmailSender Uygulama

uygulamak IEmailSenderiçin aşağıdakine benzer bir kodla oluşturun Services/EmailSender.cs :

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

Başlatmayı e-postayı destekleyecek şekilde yapılandırma

Dosyasındaki yöntemine ConfigureServices Startup.cs aşağıdaki kodu ekleyin:

  • Geçici hizmet olarak ekleyin EmailSender .
  • Yapılandırma örneğini AuthMessageSenderOptions kaydedin.
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();

yapı iskelesi RegisterConfirmation

yapı Identityiskelesi ve iskele Account\RegisterConfirmationyönergelerini izleyin.

Account.RegisterConfirmation iskelesi yapıldığında varsayılan hesap doğrulamayı devre dışı bırakma

Bu bölüm yalnızca yapı iskelesi yapıldığında Account.RegisterConfirmation geçerlidir. yapı iskelesi Account.RegisterConfirmationkurmadıysanız bu bölümü atlayın.

Kullanıcı, hesabın Account.RegisterConfirmation onaylanması için bir bağlantı seçebileceği konuma yönlendirilir. Varsayılan değer Account.RegisterConfirmation yalnızca test için kullanılır, üretim uygulamasında otomatik hesap doğrulaması devre dışı bırakılmalıdır.

Onaylanan bir hesap gerektirmek ve kayıt sırasında hemen oturum açmayı önlemek için, iskeledeki /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs dosyada ayarlayınDisplayConfirmAccountLink = false:

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable

using System;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.WebUtilities;

namespace WebPWrecover.Areas.Identity.Pages.Account
{
    [AllowAnonymous]
    public class RegisterConfirmationModel : PageModel
    {
        private readonly UserManager<IdentityUser> _userManager;
        private readonly IEmailSender _sender;

        public RegisterConfirmationModel(UserManager<IdentityUser> userManager, IEmailSender sender)
        {
            _userManager = userManager;
            _sender = sender;
        }

        /// <summary>
        ///     This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
        ///     directly from your code. This API may change or be removed in future releases.
        /// </summary>
        public string Email { get; set; }

        /// <summary>
        ///     This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
        ///     directly from your code. This API may change or be removed in future releases.
        /// </summary>
        public bool DisplayConfirmAccountLink { get; set; }

        /// <summary>
        ///     This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
        ///     directly from your code. This API may change or be removed in future releases.
        /// </summary>
        public string EmailConfirmationUrl { get; set; }

        public async Task<IActionResult> OnGetAsync(string email, string returnUrl = null)
        {
            if (email == null)
            {
                return RedirectToPage("/Index");
            }
            returnUrl = returnUrl ?? Url.Content("~/");

            var user = await _userManager.FindByEmailAsync(email);
            if (user == null)
            {
                return NotFound($"Unable to load user with email '{email}'.");
            }

            Email = email;
            // Once you add a real email sender, you should remove this code that lets you confirm the account
            DisplayConfirmAccountLink = false;
            if (DisplayConfirmAccountLink)
            {
                var userId = await _userManager.GetUserIdAsync(user);
                var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
                EmailConfirmationUrl = Url.Page(
                    "/Account/ConfirmEmail",
                    pageHandler: null,
                    values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
                    protocol: Request.Scheme);
            }

            return Page();
        }
    }
}

Bu adım yalnızca yapı iskelesi yapıldığında Account.RegisterConfirmation gereklidir. İskeleli olmayan RegisterConfirmation, bir IEmailSender'ın ne zaman uygulandığını ve bağımlılık ekleme kapsayıcısıyla ne zaman kaydedildiğini otomatik olarak algılar.

E-postayı kaydetme, onaylama ve parolayı sıfırlama

Web uygulamasını çalıştırın ve hesap onayını ve parola kurtarma akışını test edin.

  • Uygulamayı çalıştırma ve yeni bir kullanıcı kaydetme
  • Hesap onay bağlantısı için e-postanızı kontrol edin. E-postayı alamıyorsanız bkz. E-postada hata ayıklama.
  • E-postanızı onaylamak için bağlantıya tıklayın.
  • E-postanız ve parolanızla oturum açın.
  • Oturumu kapatma.

Parola sıfırlamayı test et

  • Oturum açtıysanız Oturumu Kapat'ı seçin.
  • Oturum aç bağlantısını seçin ve Parolanızı mı unuttunuz? bağlantısını seçin.
  • Hesabı kaydetmek için kullandığınız e-postayı girin.
  • Parolanızı sıfırlama bağlantısını içeren bir e-posta gönderilir. E-postanızı kontrol edin ve parolanızı sıfırlamak için bağlantıya tıklayın. Parolanız başarıyla sıfırlandıktan sonra e-postanız ve yeni parolanızla oturum açabilirsiniz.

E-posta onaylarını yeniden gönderme

ASP.NET Core 5.0 ve sonraki sürümlerde Oturum Açma sayfasındaki E-postayı yeniden gönder onay bağlantısını seçin.

E-posta ve etkinlik zaman aşımını değiştirme

Varsayılan etkinlik dışı zaman aşımı 14 gündür. Aşağıdaki kod etkinlik dışı zaman aşımını 5 güne ayarlar:

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

Tüm veri koruma belirteci kullanım ömrünü değiştirme

Aşağıdaki kod tüm veri koruma belirteçleri zaman aşımı süresini 3 saat olarak değiştirir:

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

Yerleşik Identity kullanıcı belirteçlerinin (bkz . AspNetCore/src//IdentityExtensions.Core/src/TokenOptions.cs )bir günlük zaman aşımı vardır.

E-posta belirteci kullanım ömrünü değiştirme

Kullanıcı belirteçlerinin Identity varsayılan belirteç ömrü bir gündür. Bu bölümde e-posta belirteci kullanım ömrünün nasıl değiştireceği gösterilmektedir.

Özel DataProtectorTokenProvider<TUser> ve DataProtectionTokenProviderOptionsekleyin:

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

Özel sağlayıcıyı hizmet kapsayıcısına ekleyin:

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

E-posta hatalarını ayıklama

E-postayı çalıştıramıyorsanız:

  • çağrıldığını doğrulamak SendGridClient.SendEmailAsync için içinde EmailSender.Execute bir kesme noktası ayarlayın.
  • ile benzer bir kod kullanarak e-posta göndermek için EmailSender.Executebir konsol uygulaması oluşturun.
  • E-posta Etkinliği sayfasını gözden geçirin.
  • İstenmeyen posta klasörünüzü denetleyin.
  • Farklı bir e-posta sağlayıcısında (Microsoft, Yahoo, Gmail vb.) başka bir e-posta diğer adı deneyin
  • Farklı e-posta hesaplarına göndermeyi deneyin.

Güvenlik açısından en iyi yöntem, test ve geliştirme aşamasında üretim gizli dizilerini kullanmamaktır. Uygulamayı Azure'da yayımlarsanız, Azure Web App portalında SendGrid gizli dizilerini uygulama ayarları olarak ayarlayın. Yapılandırma sistemi, ortam değişkenlerinden anahtarları okuyacak şekilde ayarlanır.

Sosyal ve yerel oturum açma hesaplarını birleştirme

Bu bölümü tamamlamak için önce bir dış kimlik doğrulama sağlayıcısını etkinleştirmeniz gerekir. Bkz . Facebook, Google ve dış sağlayıcı kimlik doğrulaması.

E-posta bağlantınıza tıklayarak yerel ve sosyal hesapları birleştirebilirsiniz. Aşağıdaki sırayla, "RickAndMSFT@gmail.com" ilk olarak yerel oturum açma olarak oluşturulur; ancak hesabı önce sosyal oturum açma olarak oluşturabilir, ardından yerel oturum açma bilgisi ekleyebilirsiniz.

Web uygulaması: RickAndMSFT@gmail.com kullanıcının kimliği doğrulandı

Yönet bağlantısına tıklayın. Bu hesapla ilişkilendirilmiş 0 harici (sosyal oturum açma bilgileri) not edin.

Görünümü yönet

Başka bir oturum açma hizmetinin bağlantısına tıklayın ve uygulama isteklerini kabul edin. Aşağıdaki görüntüde, Facebook dış kimlik doğrulama sağlayıcısıdır:

Facebook'un listelendiği dış oturum açma bilgilerinizi yönetme

İki hesap birleştirildi. İki hesapla da oturum açabilirsiniz. Kullanıcılarınızın sosyal oturum açma kimlik doğrulama hizmetinin çalışmamış olması veya sosyal hesaplarına erişimi kaybetme olasılığı daha yüksek olması durumunda yerel hesaplar eklemesini isteyebilirsiniz.

Bir sitede kullanıcılar olduktan sonra hesap onaylarını etkinleştirme

Kullanıcıların olduğu bir sitede hesap onayını etkinleştirmek, mevcut tüm kullanıcıları kilitler. Hesapları onaylanmamış olduğundan mevcut kullanıcılar kilitlenir. Mevcut kullanıcı kilitlenmesine geçici bir çözüm bulmak için aşağıdaki yaklaşımlardan birini kullanın:

  • Veritabanını, var olan tüm kullanıcıları onaylandı olarak işaretlemek için güncelleştirin.
  • Mevcut kullanıcıları onaylayın. Örneğin, onay bağlantıları içeren toplu gönderme e-postaları.