有没有人知道如何让用户通过电子邮件确认更改带有ASP.NET身份的用户名/电子邮件?有很多关于如何更改密码的例子,但是我找不到任何相关信息。
答案 0 :(得分:43)
2017年12月更新评论中提出了一些好处:
这是一个非常基本的解决方案,并未涵盖所有可能的组合,因此请使用您的判断并确保您阅读评论 - 在那里提出了非常好的观点。
// get user object from the storage
var user = await userManager.FindByIdAsync(userId);
// change username and email
user.Username = "NewUsername";
user.Email = "New@email.com";
// 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");
}
答案 1 :(得分:37)
Trailmax得到了大部分权利,但正如评论所指出的那样,如果他们在更新时搞砸了他们的新电子邮件地址,用户将会陷入困境。
要解决此问题,必须向用户类添加其他属性并修改登录。 (注意:这个答案将通过MVC 5项目解决)
这是我拍摄的地方:
<强> 1。修改您的用户对象 首先,让我们更新应用程序用户以添加我们需要的附加字段。您将在Models文件夹的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
}
跳转到我们的管理控制器中的索引操作,将其添加到我们的viewmodel:
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);
}
}
答案 2 :(得分:1)
还没有看过ChangeEmailOnIdentity2.0ASPNET,但是您是否不能利用UserName和Email值通常匹配的事实呢?这样,您可以根据要求更改“电子邮件”列,然后根据确认更改“用户名”。
这两个控制器似乎对我有用:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ChangeUserName(LoginViewModel model)
{
IdentityResult result = new IdentityResult();
try
{
if (ModelState.IsValid)
{
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
SignInStatus verify = await SignInManager.PasswordSignInAsync(user.UserName, model.Password, false, false);
if (verify != SignInStatus.Success)
{
ModelState.AddModelError("Password", "Incorrect password.");
}
else
{
if (model.Email != user.Email)
{
user.Email = model.Email;
user.EmailConfirmed = false;
// Persist the changes
result = await UserManager.UpdateAsync(user);
if (result.Succeeded)
{
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id, "Confirm your updated email", "Please confirm your email address by clicking <a href=\"" + callbackUrl + "\">this</a>");
return RedirectToAction("Index", new { Message = ManageMessageId.ChangeUserNamePending });
}
}
else
{
ModelState.AddModelError("Email", "Address specified matches current setting.");
}
}
}
}
catch (Exception ex)
{
result.Errors.Append(ex.Message);
}
AddErrors(result);
return View(model);
}
[AllowAnonymous]
public async Task<ActionResult> ConfirmEmail(string userId, string code)
{
if (userId == null || code == null)
{
return View("Error");
}
var result = await UserManager.ConfirmEmailAsync(userId, code);
if (result.Succeeded)
{
var user = await UserManager.FindByIdAsync(userId);
if (user.Email != user.UserName)
{
// Set the message to the current values before changing
String message = $"Your email user name has been changed from {user.UserName} to {user.Email} now.";
user.UserName = user.Email;
result = await UserManager.UpdateAsync(user);
if (result.Succeeded)
{
ViewBag.Message = message;
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
}
else
{
result.Errors.Append("Could not modify your user name.");
AddErrors(result);
return View("Error");
}
}
return View("ConfirmEmail");
}
else
{
return View("Error");
}
}
答案 3 :(得分:0)
我按照乔纳森(Jonathan)的步骤去了一个全新的ASP.NET项目,以测试更改,并且像个魅力一样工作。这是指向repository
的链接答案 4 :(得分:0)
万一有人在寻找使用Asp.Net Core的解决方案: 这里的事情要简单得多,请参阅SO上的这篇文章 AspNet Core Generate and Change Email Address