Подтвердить что ты не робот

Идентификация электронной почты/имени пользователя .NET

Кто-нибудь знает, как включить пользователя для изменения имени пользователя/электронной почты с идентификатором ASP.NET с подтверждением электронной почты? Есть много примеров того, как изменить пароль, но я ничего не могу найти по этому поводу.

4b9b3361

Ответ 1

Обновление декабрь 2017 В комментариях были подняты некоторые хорошие моменты:

  • Лучше иметь отдельное поле для новой электронной почты, пока оно будет подтверждено - в случаях, когда пользователь ввел неверный адрес электронной почты. Подождите, пока новое письмо не будет подтверждено, затем сделайте это основным электронным письмом. См. Очень подробный ответ от Chris_ ниже.
  • Также может быть случай, когда учетная запись с этим письмом уже существует - убедитесь, что вы это тоже проверяете, иначе могут быть проблемы.

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

// get user object from the storage
var user = await userManager.FindByIdAsync(userId);

// change username and email
user.Username = "NewUsername";
user.Email = "[email protected]";

// Persiste the changes
await userManager.UpdateAsync(user);

// generage email confirmation code
var emailConfirmationCode = await userManager.GenerateEmailConfirmationTokenAsync(user.Id);

// generate url for page where you can confirm the email
var callbackurl= "http://example.com/ConfirmEmail";

// append userId and confirmation code as parameters to the url
callbackurl += String.Format("?userId={0}&code={1}", user.Id, HttpUtility.UrlEncode(emailConfirmationCode));

var htmlContent = String.Format(
        @"Thank you for updating your email. Please confirm the email by clicking this link: 
        <br><a href='{0}'>Confirm new email</a>",
        callbackurl);

// send email to the user with the confirmation link
await userManager.SendEmailAsync(user.Id, subject: "Email confirmation", body: htmlContent);



// then this is the action to confirm the email on the user
// link in the email should be pointing here
public async Task<ActionResult> ConfirmEmail(string userId, string code)
{
    var confirmResult = await userManager.ConfirmEmailAsync(userId, code);

    return RedirectToAction("Index");
}

Ответ 2

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

Чтобы решить эту проблему, необходимо добавить дополнительные свойства в свой пользовательский класс и изменить логин. (Примечание: этот ответ будет адресован ему через проект MVC 5)

Здесь, где я взял его:

1. Измените объект пользователя Во-первых, позвольте обновить пользователя приложения, чтобы добавить дополнительное поле, которое нам понадобится. Вы добавите это в файл IdentiyModel.cs в папке "Модели":

public class ApplicationUser : IdentityUser
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        return userIdentity;
    }

    [MaxLength(256)]
    public string UnConfirmedEmail { get; set; }//this is what we add

}

Если вы хотите увидеть более подробный пример этого, посмотрите здесь http://blog.falafel.com/customize-mvc-5-application-users-using-asp-net-identity-2-0/ (это пример я используется)

Кроме того, он не упоминает об этом в связанной статье, но вы также захотите обновить таблицу AspNetUsers:

ALTER TABLE dbo.AspNetUsers
ADD [UnConfirmedEmail] NVARCHAR(256) NULL;

2. Обновите свой логин

Теперь нам нужно убедиться, что наш логин проверяет прежнее подтверждение по электронной почте, так что все может быть "в неопределенности", пока мы ждем, когда пользователь подтвердит это новое электронное письмо:

   //
    // POST: /Account/Login
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }

        var allowPassOnEmailVerfication = false;
        var user = await UserManager.FindByEmailAsync(model.Email);
        if (user != null)
        {
            if (!string.IsNullOrWhiteSpace(user.UnConfirmedEmail))
            {
                allowPassOnEmailVerfication = true;
            }
        }


        // This now counts login failures towards account lockout
        // To enable password failures to trigger account lockout, I changed to shouldLockout: true
        var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: true);
        switch (result)
        {
            case SignInStatus.Success:
                return RedirectToLocal(returnUrl);
            case SignInStatus.LockedOut:
                return View("Lockout");
            case SignInStatus.RequiresVerification:
                return allowPassOnEmailVerfication ? RedirectToLocal(returnUrl) : RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
            case SignInStatus.Failure:
            default:
                ModelState.AddModelError("", "Invalid login attempt.");
                return View(model);
        }
    }

Что это... ты по существу сделан! Тем не менее, меня всегда раздражает половина ответов, которые не проходят мимо потенциальных ловушек, которые вы нажмете позже, так что продолжайте наше приключение, не так ли?

3. Обновите управление/индекс

В нашем index.cshtml добавьте новый раздел для электронной почты. Прежде чем мы туда доберемся, отпустите добавьте поле, которое нам нужно в ManageViewmodel.cs

public class IndexViewModel
{
    public bool HasPassword { get; set; }
    public IList<UserLoginInfo> Logins { get; set; }
    public string PhoneNumber { get; set; }
    public bool TwoFactor { get; set; }
    public bool BrowserRemembered { get; set; }

    public string ConfirmedEmail { get; set; } //add this
    public string UnConfirmedEmail { get; set; } //and this
}

Перейдите в действие индекса в нашем диспетчере управления, чтобы добавить это в нашу модель просмотра:

        var userId = User.Identity.GetUserId();
        var currentUser = await UserManager.FindByIdAsync(userId);

        var unConfirmedEmail = "";
        if (!String.IsNullOrWhiteSpace(currentUser.UnConfirmedEmail))
        {
            unConfirmedEmail = currentUser.UnConfirmedEmail;
        }
        var model = new IndexViewModel
        {
            HasPassword = HasPassword(),
            PhoneNumber = await UserManager.GetPhoneNumberAsync(userId),
            TwoFactor = await UserManager.GetTwoFactorEnabledAsync(userId),
            Logins = await UserManager.GetLoginsAsync(userId),
            BrowserRemembered = await AuthenticationManager.TwoFactorBrowserRememberedAsync(userId),
            ConfirmedEmail = currentUser.Email,
            UnConfirmedEmail = unConfirmedEmail
        };

Наконец, для этого раздела мы можем обновить наш индекс, чтобы мы могли управлять этой новой электронной почтой:

<dt>Email:</dt>
    <dd>
        @Model.ConfirmedEmail
        @if (!String.IsNullOrWhiteSpace(Model.UnConfirmedEmail))
        {
            <em> - Unconfirmed: @Model.UnConfirmedEmail </em> @Html.ActionLink("Cancel", "CancelUnconfirmedEmail",new {email=Model.ConfirmedEmail})
        }
        else
        {
            @Html.ActionLink("Change Email", "ChangeEmail")
        }
    </dd>

4. Добавьте эти новые изменения

Сначала добавьте ChangeEmail:

Просмотр модели:

public class ChangeEmailViewModel
{
    public string ConfirmedEmail { get; set; } 
    [Required]
    [EmailAddress]
    [Display(Name = "Email")]
    [DataType(DataType.EmailAddress)]
    public string UnConfirmedEmail { get; set; } 
}

Получить действие:

 public ActionResult ChangeEmail()
    {
        var user = UserManager.FindById(User.Identity.GetUserId());
        var model = new ChangeEmailViewModel()
        {
            ConfirmedEmail = user.Email
        };

        return View(model);
    }

Вид:

@model ProjectName.Models.ChangeEmailViewModel
@{
ViewBag.Title = "Change Email";
}

<h2>@ViewBag.Title.</h2>

@using (Html.BeginForm("ChangeEmail", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
    @Html.AntiForgeryToken()
    <h4>New Email Address:</h4>
    <hr />
    @Html.ValidationSummary("", new { @class = "text-danger" })
    @Html.HiddenFor(m=>m.ConfirmedEmail)
    <div class="form-group">
        @Html.LabelFor(m => m.UnConfirmedEmail, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.UnConfirmedEmail, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" class="btn btn-default" value="Email Link" />
        </div>
    </div>
}

Действие HttpPost:

    [HttpPost]
    public async Task<ActionResult> ChangeEmail(ChangeEmailViewModel model)
    {
        if (!ModelState.IsValid)
        {
            return RedirectToAction("ChangeEmail", "Manage");
        }

        var user = await UserManager.FindByEmailAsync(model.ConfirmedEmail);
        var userId = user.Id;
        if (user != null)
        {
            //doing a quick swap so we can send the appropriate confirmation email
            user.UnConfirmedEmail = user.Email;
            user.Email = model.UnConfirmedEmail;
            user.EmailConfirmed = false;
            var result = await UserManager.UpdateAsync(user);

            if (result.Succeeded)
            {

                string callbackUrl =
                await SendEmailConfirmationTokenAsync(userId, "Confirm your new email");

                var tempUnconfirmed = user.Email;
                user.Email = user.UnConfirmedEmail;
                user.UnConfirmedEmail = tempUnconfirmed;
                result = await UserManager.UpdateAsync(user);

                callbackUrl = await SendEmailConfirmationWarningAsync(userId, "You email has been updated to: "+user.UnConfirmedEmail);


            }
        }
        return RedirectToAction("Index","Manage");
    }

Теперь добавьте это предупреждение:

    private async Task<string> SendEmailConfirmationWarningAsync(string userID, string subject)
    {
        string code = await UserManager.GenerateEmailConfirmationTokenAsync(userID);
        var callbackUrl = Url.Action("ConfirmEmail", "Account",
           new { userId = userID, code = code }, protocol: Request.Url.Scheme);
        await UserManager.SendEmailAsync(userID, subject,
           "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>");

        return callbackUrl;
    }

И теперь, наконец, мы можем отменить новый адрес электронной почты:

    public async Task<ActionResult> CancelUnconfirmedEmail(string emailOrUserId)
    {
        var user = await UserManager.FindByEmailAsync(emailOrUserId);
        if (user == null)
        {
            user = await UserManager.FindByIdAsync(emailOrUserId);
            if (user != null)
            {
                user.UnConfirmedEmail = "";
                user.EmailConfirmed = true;
                var result = await UserManager.UpdateAsync(user);
            }
        }
        else
        {
            user.UnConfirmedEmail = "";
            user.EmailConfirmed = true;
            var result = await UserManager.UpdateAsync(user);
        }
        return RedirectToAction("Index", "Manage");

    }

5. Обновить ConfirmEmail (самый последний шаг)

После всего этого назад и вперед мы можем подтвердить новое электронное письмо, что означает, что мы должны одновременно удалить старую электронную почту.

 var result = UserManager.ConfirmEmail(userId, code);
 if (result.Succeeded)
 {

     var user = UserManager.FindById(userId);
     if (!string.IsNullOrWhiteSpace(user.UnConfirmedEmail))
     {
         user.Email = user.UnConfirmedEmail;
         user.UserName = user.UnConfirmedEmail;
         user.UnConfirmedEmail = "";

         UserManager.Update(user);
     }
 }