【问题标题】:Asp.net core identity change username/emailAsp.net 核心身份更改用户名/电子邮件
【发布时间】:2019-01-11 22:27:17
【问题描述】:

带有确认逻辑的默认身份更改用户名/电子邮件没有意义。

  • 设置应用需要电子邮件确认。
  • 设置需要确认的电子邮件才能登录。
  • 用户然后更改电子邮件,输入错误的电子邮件,注销。
  • 现在用户被锁定。电子邮件已更改但需要 确认登录,没有电子邮件确认链接,因为 地址输入错误。

是我错误地设置了我的应用程序还是 Microsoft 没有很好地设计 Identity?

  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 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}'.");
                }
                StatusMessage = "<strong>Verify your new email</strong><br/><br/>" +
                    "We sent an email to " + Input.Email +
                    " to verify your address. Please click the link in that email to continue.";
            }

  //...


        await _signInManager.RefreshSignInAsync(user);

        return RedirectToPage();
    }

【问题讨论】:

  • 您能否编辑您的问题并包含您用于更改电子邮件控制器的代码?在用户确认之前,您不应该实际保存更改的电子邮件地址。
  • @DaImTo 我已经更新了我的问题。它是 identity/pages/account/manage 中 index.cshtml 页面的默认脚手架。
  • 默认从哪里来?我会说那是错误的,因为它甚至没有发送构造代码。
  • 创建新的 asp.net core web 应用程序(asp.net core 2.2,mvc)。添加身份脚手架。在 Areas/identity/pages/account/manage/Index.cshtml.cs
  • 这就是我的意思,它并没有按照您的预期去做。我知道模板只是项目的起点,但我希望用户管理/配置文件/身份代码更加完善。特别是考虑到 asp.net 已经 17 岁了...

标签: asp.net-core asp.net-identity


【解决方案1】:

您的问题是为此目的使用SetEmailAsync。该方法旨在为用户设置电子邮件当前不存在时。在这种情况下,将确认设置为 false 是有意义的,不会导致任何问题。

还有另一种方法,ChangeEmailAsync,这是您应该使用的方法。此方法需要一个令牌,该令牌将从电子邮件确认流程中获得。换句话说,您应该采取的步骤是:

  1. 用户提交带有新电子邮件的表单以更改为
  2. 您向用户发送确认电子邮件。用户要更改的电子邮件地址需要保留在确认链接中或数据库中的单独位置。换句话说,用户在其用户记录中的实际电子邮件没有改变。
  3. 用户单击电子邮件中的确认链接。您可以从链接或您之前保存的任何位置获得他们想要更改的新电子邮件地址
  4. 您使用此电子邮件和来自确认链接的令牌致电 ChangeEmailAsync。
  5. 用户的电子邮件现已更改并确认。

编辑

FWIW,是的,这似乎是默认模板的问题。不知道他们为什么这样做,因为是的,它非常破坏了事情,就像我在回答中所说的那样,ChangeEmailAsync 就是为此目的而存在的。只需按照我上面概述的步骤并在此处更改用户通过“管理”页面提交新电子邮件地址时发生的情况的逻辑。

编辑#2

我已经为此提交了issue on Github。我现在不能再花时间在这上面了,但是如果我有时间并且没有其他人能比我做得更好,我会尝试提交一个修复请求。修复相对简单。

编辑#3

我能够在分叉中获得基本的电子邮件更改流程。但是,该团队已经分配了该问题,并且似乎将其作为身份 UI 大修的一部分。我现在可能不会再为此投入任何时间,但鼓励您关注该问题以获取团队的更新。如果您现在碰巧借用我的代码来实施修复,请注意我正在尝试创建一个对其他代码具有最小熵的解决方案。例如,在实际的生产应用程序中,您应该将新电子邮件保存在数据库中的某个位置,而不是在 URL 中传递它。

【讨论】:

  • 你说的ChangeEmailAsync这个方法是什么,我没看到?
  • UserManager 已关闭。
  • v2.2.2没有出现,你看的是什么版本?
  • 所有版本都有。它一直都在。 docs.microsoft.com/en-us/dotnet/api/…
  • 有趣,因为它不在我的手中。想知道使用UserManager&lt;TUser, TKey&gt; 是否有问题,因为我使用long 而不是string 代替TKey?
【解决方案2】:

如前所述,模板肯定提供了错误的行为。您可以在https://github.com/aspnet/Scaffolding repo here 中查看模板的来源。

我建议在 GitHub 项目上提出一个问题,以便对此进行更改。当模板更新时,他们无疑必须考虑启用确认和未启用确认的情况。在您的情况下,您可以相对轻松地重用 OnPostSendVerificationEmailAsync() 中已经存在的逻辑。

更通用的实现如下所示:

public partial class IndexModel : PageModel
{
    // inject as IOptions<IdentityOptions> into constructor
    private readonly IdentityOptions _options;

    // Extracted from OnPostSendVerificationEmailAsync()
    private async Task SendConfirmationEmail(IdentityUser user, string email)
    {
        var userId = await _userManager.GetUserIdAsync(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>.");
    }

    public async Task<IActionResult> OnPostAsync()
    {
        //... Existing code

        var email = await _userManager.GetEmailAsync(user);
        var confirmationEmailSent = false;
        if (Input.Email != email)
        {
            if(_options.SignIn.RequireConfirmedEmail)
            {
                // new implementation
                await SendConfirmationEmail(user, Input.Email);
                confirmationEmailSent = true;
            }
            else
            {
                // current implementation
                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}'.");
                }
            }
            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}'.");
            }
        }

        // existing update phone number code;

        await _signInManager.RefreshSignInAsync(user);
        StatusMessage = confirmationEmailSent 
            ? "Verification email sent. Please check your email."
            : "Your profile has been updated";
        return RedirectToPage();
    }


    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 email = await _userManager.GetEmailAsync(user);
        await SendConfirmationEmail(user, email);

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

【讨论】:

    猜你喜欢
    • 2014-10-23
    • 1970-01-01
    • 2020-09-08
    • 1970-01-01
    • 2020-07-13
    • 1970-01-01
    • 2013-11-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多