Asp.net основной идентификатор изменить имя пользователя / адрес электронной почты - PullRequest
0 голосов
/ 10 января 2019

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

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

Неправильно ли я настроил свое приложение или 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();
    }

Ответы [ 2 ]

0 голосов
/ 10 января 2019

Как уже определено, шаблон определенно обеспечивает неправильное поведение. Вы можете увидеть источник шаблона в https://github.com/aspnet/Scaffolding репо здесь .

Я предлагаю поднять проблему в проекте 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();
    }
}
0 голосов
/ 10 января 2019

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

Есть еще один метод, ChangeEmailAsync, который вы должны использовать. Этот метод требует токен, который будет получен из потока подтверждения электронной почты. Другими словами, шаги, которые вы должны сделать:

  1. Пользователь отправляет форму с новым адресом электронной почты для изменения на
  2. Вы отправляете электронное письмо с подтверждением пользователю. Адрес электронной почты, на который изменяется пользователь, необходимо сохранить либо в ссылке для подтверждения, либо в отдельном месте в вашей базе данных. Другими словами, фактическая электронная почта пользователя в его записи не изменилась .
  3. Пользователь нажимает ссылку для подтверждения по электронной почте. Вы получаете новый адрес электронной почты, который они хотят изменить, либо по ссылке, либо там, где вы сохранили ее ранее
  4. Вы звоните ChangeEmailAsync с этим электронным письмом и токеном из ссылки для подтверждения.
  5. Электронная почта пользователя теперь изменена и подтверждена.

EDIT

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

РЕДАКТИРОВАТЬ # 2

Я подал проблему на Github для этого. Сейчас я не могу больше уделять этому времени, но я попытаюсь отправить запрос на исправление, если у меня есть время, и никто больше меня не побеждает. Исправление относительно простое.

РЕДАКТИРОВАТЬ # 3

Мне удалось заставить основной поток изменений электронной почты работать в форке. Тем не менее, команда уже определила проблему и, кажется, включает ее как часть более серьезного пересмотра интерфейса Identity. Я, скорее всего, не буду больше уделять этому времени сейчас, но призываю вас следить за обновлениями от команды. Если вам случится позаимствовать из моего кода для реализации исправления сейчас, имейте в виду, что я пытался создать решение с минимальной энтропией к другому коду. В реальном производственном приложении вы должны сохранить новое электронное письмо где-нибудь, например, в базе данных, а не передавать его, например, в URL.

...