asp.net - tutorial - authorized asp net core




.NET Identity Email/Username Änderung (4)

Weiß jemand, wie ein Benutzer das Ändern des Benutzernamens / der E-Mail mit der ASP.NET-Identität mit der E-Mail-Bestätigung ermöglicht? Es gibt viele Beispiele, wie man das Passwort ändert, aber ich kann nichts dazu finden.



Ich folgte den Schritten von Jonathan zu einem brandneuen ASP.NET-Projekt, um die Änderungen zu testen, und arbeitete wie ein Zauber. Dies ist der Link zum ChangeEmailOnIdentity2.0ASPNET


Trailmax hat das meiste richtig gemacht, aber wie aus den Kommentaren hervorgeht, wäre der Benutzer im Wesentlichen gestrandet, wenn er beim Aktualisieren seine neue E-Mail-Adresse durcheinanderbringen würde.

Um dies zu beheben, müssen Sie Ihrer Benutzerklasse zusätzliche Eigenschaften hinzufügen und die Anmeldung ändern. (Hinweis: Diese Antwort wird über ein MVC 5-Projekt angesprochen.)

Hier habe ich es aufgenommen:

1. Ändern Sie Ihr Benutzerobjekt. Zuerst aktualisieren Sie den Anwendungsbenutzer, um das zusätzliche Feld hinzuzufügen, das wir benötigen. Sie fügen dies der Datei IdentiyModel.cs in Ihrem Ordner "Models" hinzu:

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

}

Wenn Sie ein ausführlicheres Beispiel sehen möchten, lesen Sie hier http://blog.falafel.com/customize-mvc-5-application-users-using-asp-net-identity-2-0/ (das ist das Beispiel, das ich verwendet habe)

Außerdem wird es in dem verknüpften Artikel nicht erwähnt, aber Sie sollten auch Ihre AspNetUsers-Tabelle aktualisieren:

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

2. Aktualisieren Sie Ihr Login

Jetzt müssen wir sicherstellen, dass unser Login auch die alte E-Mail-Bestätigung überprüft, sodass Dinge "in der Luft" sein können, während wir darauf warten, dass der Benutzer diese neue E-Mail bestätigt:

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

Das ist es ... du bist im Wesentlichen fertig! Allerdings ärgere ich mich immer über die halben Antworten, die dich nicht an potenziellen Fallen vorbeikommen, die du später triffst, also lass uns unser Abenteuer fortsetzen, oder?

3. Aktualisieren Sie Ihr Manage / Index

Fügen Sie in unserer index.cshtml einen neuen Abschnitt für E-Mail hinzu. Bevor wir jedoch dorthin gelangen, fügen wir das Feld hinzu, das wir in ManageViewmodel.cs benötigen

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
}

Wechseln Sie in die Index-Aktion in unserem Manage-Controller, um dies unserem Viewmodel hinzuzufügen:

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

Schließlich können wir für diesen Abschnitt unseren Index aktualisieren, um diese neue E-Mail-Option verwalten zu können:

<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. Fügen Sie diese neuen Änderungen hinzu

Zuerst fügen wir ChangeEmail hinzu:

Modell anzeigen:

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

Action bekommen:

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

        return View(model);
    }

Aussicht:

@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-Aktion:

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

Fügen Sie nun diese Warnung hinzu:

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

Und endlich können wir die neue E-Mail-Adresse stornieren:

    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. Update ConfirmEmail (der allerletzte Schritt)

Nach all dem hin und her können wir nun die neue E-Mail bestätigen, was bedeutet, dass wir die alte E-Mail gleichzeitig entfernen sollten.

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

Update Dezember 2017 In den Kommentaren wurden einige gute Punkte angesprochen:

  • Besser haben Sie ein separates Feld für neue E-Mails, wenn diese bestätigt werden - in Fällen, in denen der Benutzer eine falsche E-Mail eingegeben hat. Warten Sie, bis die neue E-Mail bestätigt wurde, und machen Sie sie dann zur primären E-Mail. Siehe sehr detaillierte Antwort von Chris_ unten.
  • Es kann auch vorkommen, dass bereits ein Konto mit dieser E-Mail vorhanden ist. Stellen Sie sicher, dass auch dies überprüft wird. Andernfalls können Probleme auftreten.

Dies ist eine sehr einfache Lösung, die nicht alle möglichen Kombinationen abdeckt. Verwenden Sie Ihr Urteilsvermögen und stellen Sie sicher, dass Sie die Kommentare durchlesen. Hier wurden sehr gute Punkte angesprochen.

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




asp.net-identity