具有确认逻辑的默认身份更改用户名/电子邮件没有任何意义。
我是否设置了错误的应用程序,或者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();
}
答案 0 :(得分:2)
您的问题为此使用了SetEmailAsync
。该方法旨在为用户当前不存在的电子邮件设置电子邮件。在这种情况下,将Confirmed设置为false是有道理的,不会造成任何问题。
还有另一种方法ChangeEmailAsync
,这是您应该使用的方法。此方法需要令牌,可以从电子邮件确认流程中获取令牌。换句话说,您应该执行的步骤是:
ChangeEmailAsync
。编辑
FWIW,是的,这似乎是默认模板的问题。不知道为什么要这样做,因为是的,它很容易出错,就像我在回答中所说的那样,ChangeEmailAsync
就是为此目的而存在的。只需按照我上面概述的步骤操作,然后在此处更改当用户通过“管理”页面提交新的电子邮件地址时发生的逻辑。
编辑#2
我为此提交了issue on Github。我现在不能再花时间了,但是如果我有时间并且没有其他人击败我,我将尝试提交拉动请求以进行修复。解决方法相对简单。
编辑#3
我能够轻松地进行基本的电子邮件更改流程。但是,团队已经分配了该问题,并且似乎已将其包含在Identity UI的较大检查中。我现在可能不会再花时间在此上了,但鼓励您关注此问题以获取团队的更新。如果您确实想借用我的代码来立即实施修复,则建议我尝试创建一种对其他代码的熵最小的解决方案。在实际的生产应用中,您应该将新电子邮件保留在数据库中的某个位置,而不是例如将其传递到URL中。
答案 1 :(得分:1)
正如已经确定的,该模板肯定提供了错误的行为。您可以在https://github.com/aspnet/Scaffolding存储库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();
}
}