要求在ASP.NET Core 2.2中确认电子邮件——第2部分

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mzl87/article/details/85625176

目录

介绍

使用代码

先决条件

步骤1——将UnconfirmedEmail属性添加到IdentityUser

第2步——更新数据库

第3步——添加更改电子邮件页面

第4步——修改配置文件

第5步——重写UserManager


在新的ASP.NET Core 2.2 Razor页面模板中支持并修改Identity

介绍

ASP.NET Core 2.2 Web应用程序2部分中的第2部分,允许用户更新已确认的电子邮件。以下是允许用户更新其电子邮件的步骤。

要求在ASP.NET Core 2.2中确认电子邮件——第1部分

使用代码

先决条件

  • .NET Core 2.2 SDK
  • 以下VS中的一个:
    • Visual Studio版本201715.9或更高版本
    • Visual Studio for Mac 7.7或更高版本
    • Visual Studio Code C#扩展版本1.17.1或更高版本

您可以在完成第1部分中的步骤后下载VS 2017项目或按照以下步骤修改您自己的项目。

步骤1——将UnconfirmedEmail属性添加到IdentityUser

Entities文件夹中添加命名为ApplicationUser的新类:

using Microsoft.AspNetCore.Identity;

namespace <YourProjectName>.Entities
{
    public class ApplicationUser : IdentityUser
    {
        [PersonalData]
        public string UnconfirmedEmail { get; set; }
    }
}

使用查找和替换,以当前工程中替换<IdentityUser><ApplicationUser>

使用ApplicationUser编辑Startup.cs > ConfigureServices

services.AddIdentity<ApplicationUser, IdentityRole>

编辑Areas\Identity\Pages\Account\Manage\EnableAuthenticator.cshtml.cs:

private async Task LoadSharedKeyAndQrCodeUriAsync(ApplicationUser user)

编辑Areas\Identity\Pages\Account\Manage\DownloadPersonalData.cshtml.cs:

var personalDataProps = typeof(ApplicationUser).GetProperties().Where(
                        prop => Attribute.IsDefined(prop, typeof(PersonalDataAttribute)));

编辑Areas\Identity\Pages\Account\ExternalLogin.cshtml.cs

var user = new ApplicationUser { UserName = Input.Email, Email = Input.Email };

编辑Register.cshtml.cs

var user = new ApplicationUser { UserName = Input.UserName, Email = Input.Email };

解决替换IdentityUser的命名空间问题。

using <YourProjectName>.Entities;

或者用于cshtml

@using <YourProjectName>.Entities;

构建项目并检查错误。

2步——更新数据库

编辑在Data文件夹中的ApplicationDbContext,添加ApplicationUser

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>

VS 2017中的程序包管理器控制台运行命令 Add-Migration UnconfirmedEmail ”

运行命令“ Update-Database

3步——添加更改电子邮件页面

编辑ManageNavPages.cs,在上面添加ChangePassword属性:

public static string ChangeEmail => "ChangeEmail";

和:

public static string ChangeEmailNavClass(ViewContext viewContext) =>
                                         PageNavClass(viewContext, ChangeEmail);

编辑_ManageNav.cshtml,在下面添加个人资料项:

<li class="nav-item">
<a class="nav-link @ManageNavPages.ChangeEmailNavClass(ViewContext)"
 id="change-email" asp-page="./ChangeEmail">Email</a></li>

Areas\Identity\Pages\Account\Manage中创建名为ChangeEmailrazer页面。

编辑ChangeEmail.cshtml

@page
@model ChangeEmailModel
@{
    ViewData["Title"] = "Change Email";
    ViewData["ActivePage"] = ManageNavPages.ChangeEmail;
}

<h4>@ViewData["Title"]</h4>
<partial name="_StatusMessage" for="StatusMessage" />

<div class="row">
    <div class="col-md-6">
        <form id="change-email-form" method="post">
            <div asp-validation-summary="All" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Email"></label>
                <input asp-for="Email" class="form-control" disabled />
            </div>

            <h5>New email needs to be verified.</h5>
            <div class="form-group">
                <label asp-for="Input.Email"></label>
                <input asp-for="Input.Email" class="form-control" />
                <span asp-validation-for="Input.Email" class="text-danger"></span>
            </div>
            <button type="submit" class="btn btn-primary">Update Email</button>
        </form>
    </div>
</div>

@section Scripts {
<partial name="_ValidationScriptsPartial" />

}

编辑ChangeEmail.cshtml.cs

using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using <YourProjectName>.Services;
using <YourProjectName>.Entities;

namespace <YourProjectName>.Areas.Identity.Pages.Account.Manage
{
    public class ChangeEmailModel : PageModel
    {
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly SignInManager<ApplicationUser> _signInManager;
        private readonly ILogger<ChangeEmailModel> _logger;
        private readonly IEmailSender _emailSender;

        public ChangeEmailModel(
            UserManager<ApplicationUser> userManager,
            SignInManager<ApplicationUser> signInManager,
            ILogger<ChangeEmailModel> logger,
            IEmailSender emailSender)
        {
            _userManager = userManager;
            _signInManager = signInManager;
            _logger = logger;
            _emailSender = emailSender;
        }

        [BindProperty]
        public InputModel Input { get; set; }

        [TempData]
        [Display(Name = "Verified Email")]
        public string Email { get; set; }

        [TempData]
        public string StatusMessage { get; set; }

        public class InputModel
        {
            [Required]
            [EmailAddress]
            [Display(Name = "New Email")]
            public string Email { get; set; }
        }

        public async Task<IActionResult> OnGetAsync()
        {
            var user = await _userManager.GetUserAsync(User);
            if (user == null)
            {
                return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
            }

            var email = await _userManager.GetEmailAsync(user);

            Email = email;

            return Page();
        }

        public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            var user = await _userManager.GetUserAsync(User);
            if (user == null)
            {
                return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
            }

            var email = await _userManager.GetEmailAsync(user);
            if (Input.Email != email)
            {
                var errors = new List<IdentityError>();
                if (_userManager.Options.User.RequireUniqueEmail)
                {
                    var owner = await _userManager.FindByEmailAsync(Input.Email);
                    if (owner != null && !string.Equals
                       (await _userManager.GetUserIdAsync(owner), 
                        await _userManager.GetUserIdAsync(user)))
                    {
                        ModelState.AddModelError(string.Empty, 
                        new IdentityErrorDescriber().DuplicateEmail(Input.Email).Description);
                        return Page();
                    }
                }

                var setEmailResult = await _userManager.SetEmailAsync(user, Input.Email);
                if (!setEmailResult.Succeeded)
                {
                    var userId = await _userManager.GetUserIdAsync(user);
                    throw new InvalidOperationException($"Unexpected error occurred 
                                       setting email for user with ID '{userId}'.");
                }

                if (Input.Email.ToUpper() != email.ToUpper())
                {
                    var result = await _userManager.UpdateSecurityStampAsync(user);
                    if (!result.Succeeded)
                    {
                        foreach (var error in result.Errors)
                        {
                            ModelState.AddModelError(string.Empty, error.Description);
                            return Page();
                        }
                    }

                    var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);

                    var callbackUrl = Url.Page(
                        "/Account/ConfirmEmail",
                        pageHandler: null,
                        values: new { userId = user.Id, code = code },
                        protocol: Request.Scheme);

                    await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
                        $"Please confirm your account by 
                        <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");

                    _logger.LogInformation("User updated their UnconfirmedEmail.");
                    StatusMessage = "Please check your inbox to confirm the new email.";

                }
                else
                {
                    _logger.LogInformation("User updated their Email.");
                    StatusMessage = "Your email has been updated.";
                }
            }

            return RedirectToPage();
        }
    }
}

4步——修改配置文件

Areas\Identity\Pages\Account\Manage中编辑Index.cshtml.cs使用新的ChangeEmail页面。

添加:

public string Email { get; set; }

去掉:

public bool IsEmailConfirmed { get; set; }

InputModel中删除:

[Required]
[EmailAddress]
public string Email { get; set; }

OnGetAsync>Input中删除:

Email = email,

OnGetAsync中删除:

IsEmailConfirmed = await _userManager.IsEmailConfirmedAsync(user);

OnPostAsync中删除:

var email = await _userManager.GetEmailAsync(user);
if (Input.Email != email)
{
    var setEmailResult = await _userManager.SetEmailAsync(user, Input.Email);
    if (!setEmailResult.Succeeded)
    {
        var userId = await _userManager.GetUserIdAsync(user);
        throw new InvalidOperationException($"Unexpected error occurred
                     setting email for user with ID '{userId}'.");
     }
 }

删除:

public async Task<IActionResult> OnPostSendVerificationEmailAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    var user = await _userManager.GetUserAsync(User);
    if (user == null)
    {
        return NotFound($"Unable to load user with ID '
        {_userManager.GetUserId(User)}'.");
    }


    var userId = await _userManager.GetUserIdAsync(user);
    var email = await _userManager.GetEmailAsync(user);
    var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
    var callbackUrl = Url.Page(
        "/Account/ConfirmEmail",
        pageHandler: null,
        values: new { userId = userId, code = code },
        protocol: Request.Scheme);
    await _emailSender.SendEmailAsync(
        email,
        "Confirm your email",
        $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode
                                         (callbackUrl)}' >clicking here</a>.");

    StatusMessage = "Verification email sent. Please check your email.";
    return RedirectToPage();
}

编辑Index.cshtml

更换:

@if (Model.IsEmailConfirmed)
{
<div class="input-group">
<input asp-for="Input.Email" class="form-control" />

<span class="input-group-addon" aria-hidden="true">
<span class="glyphicon glyphicon-ok text-success"></span></span>
</div>
}
else
{
<input asp-for="Input.Email" class="form-control" />

<button id="email-verification" type="submit" asp-page-handler="SendVerificationEmail" 

class="btn btn-link">Send verification email</button>
}
<span asp-validation-for="Input.Email" class="text-danger"></span>

使用:

<input asp-for="Email" class="form-control" disabled />

5步——重写UserManager

Services文件夹中添加命名为ApplicationUserManager的新类:

using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using <YourProjectName>.Entities;

namespace <YourProjectName>.Services
{
    public class ApplicationUserManager : UserManager<ApplicationUser>
    {
        public ApplicationUserManager(IUserStore<ApplicationUser> store,
            IOptions<IdentityOptions> optionsAccessor,
            IPasswordHasher<ApplicationUser> passwordHasher,
            IEnumerable<IUserValidator<ApplicationUser>> userValidators,
            IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators,
            ILookupNormalizer keyNormalizer,
            IdentityErrorDescriber errors,
            IServiceProvider services,
            ILogger<UserManager<ApplicationUser>> logger)
            : base(store, optionsAccessor, passwordHasher, userValidators,
                  passwordValidators, keyNormalizer, errors, services, logger)
        {
        }

        /// <summary>
        /// Sets the <paramref name="email"/> address for a <paramref name="user"/>.
        /// </summary>
        /// <param name="user">The user whose email should be set.</param>
        /// <param name="email">The email to set.</param>
        /// <returns>
        /// The <see cref="Task"/> that represents the asynchronous operation, 
        /// containing the <see cref="IdentityResult"/>
        /// of the operation.
        /// </returns>
        public override async Task<IdentityResult> SetEmailAsync(ApplicationUser user, string email)
        {
            ThrowIfDisposed();
            if (user == null)
            {
                throw new ArgumentNullException(nameof(user));
            }

            if (user.EmailConfirmed && user.Email.ToUpper() != email.ToUpper())
                user.UnconfirmedEmail = email;
            else
                user.Email = email;

            return await UpdateUserAsync(user);
        }

        /// <summary>
        /// Validates that an email confirmation token matches the specified 
        /// <paramref name="user"/> and if successful sets
        /// EmailConfirmed to true and if UnconfirmedEmail is not NULL or Empty, 
        /// copies the user's UnconfirmedEmail to user's
        /// Email and sets UnconfirmedEmail to NULL.
        /// </summary>
        /// <param name="user">The user to validate the token against.</param>
        /// <param name="token">The email confirmation token to validate.</param>
        /// <returns>
        /// The <see cref="Task"/> that represents the asynchronous operation, 
        /// containing the <see cref="IdentityResult"/>
        /// of the operation.
        /// </returns>
        public override async Task<IdentityResult> 
                  ConfirmEmailAsync(ApplicationUser user, string token)
        {
            ThrowIfDisposed();
            if (user == null)
            {
                throw new ArgumentNullException(nameof(user));
            }

            IdentityResult result;
            var provider = Options.Tokens.EmailConfirmationTokenProvider;
            var isValidToken = await base.VerifyUserTokenAsync
                               (user, provider, "EmailConfirmation", token);

            if (isValidToken)
            {
                if (!string.IsNullOrEmpty(user.UnconfirmedEmail))
                {
                    user.Email = user.UnconfirmedEmail;
                    user.UnconfirmedEmail = null;
                }
                user.EmailConfirmed = true;
                result = await UpdateUserAsync(user);
            }
            else
            {
                result = IdentityResult.Failed(new IdentityErrorDescriber().InvalidToken());
            }

            return result;
        }
    }
}

编辑Startup.cs > ConfigureServices,添加.AddUserManager<ApplicationUserManager>()

services.AddIdentity<ApplicationUser, IdentityRole>(config =>
    {
        config.SignIn.RequireConfirmedEmail = true;
        config.User.RequireUniqueEmail = true;
    })
    .AddDefaultUI(UIFramework.Bootstrap4)
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddUserManager<ApplicationUserManager>()
    .AddDefaultTokenProviders();

构建并测试项目。

 

原文地址:https://www.codeproject.com/Articles/1272510/Require-Confirmed-Email-in-ASP-NET-Core-2-2-Part-2

猜你喜欢

转载自blog.csdn.net/mzl87/article/details/85625176