ASP.NET Core Identity 使用UserManager无需邮箱确认修改用户邮箱的实现问题
错误原因说明
- 调用
ChangeEmailAsync报令牌无效的原因:你生成更改邮箱令牌后,执行了WebEncoders.Base64UrlEncode编码操作,这个编码是为了把令牌放到URL参数里传输用的,你直接把编码后的令牌传给ChangeEmailAsync方法,方法识别不了自然报令牌无效。 - 直接修改用户实体Email属性不生效的原因:你只修改了内存中实体的属性值,没有调用
UpdateAsync方法把变更提交到数据库,而且漏了NormalizedEmail标准化邮箱字段的更新,会导致后续Identity查询逻辑异常。
可选解决方案
方案1:修正令牌调用逻辑
直接删掉令牌编码的代码即可,生成的原始令牌可以直接传入ChangeEmailAsync使用:
public async Task<IActionResult> OnPostChangeEmailAsync() { var user = await _userManager.GetUserAsync(User); if (user == null) { return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); } if (!ModelState.IsValid) { await LoadAsync(user); return Page(); } var email = await _userManager.GetEmailAsync(user); if (Input.NewEmail != email) { var code = await _userManager.GenerateChangeEmailTokenAsync(user, Input.NewEmail); // 移除多余的令牌编码逻辑 var changeResult = await _userManager.ChangeEmailAsync(user, Input.NewEmail, code); if (!changeResult.Succeeded) { foreach (var error in changeResult.Errors) { ModelState.AddModelError(string.Empty, error.Description); } await LoadAsync(user); return Page(); } // 可选:同步将邮箱状态设为已确认 await _userManager.SetEmailConfirmedAsync(user, true); StatusMessage = "邮箱已修改成功"; return RedirectToPage(); } StatusMessage = "邮箱未发生变更"; return RedirectToPage(); }
方案2:直接更新用户实体(完全跳过令牌验证)
如果不需要走Identity默认的令牌验证流程,可以直接修改用户的邮箱相关字段后提交更新,代码更简洁:
public async Task<IActionResult> OnPostChangeEmailAsync() { var user = await _userManager.GetUserAsync(User); if (user == null) { return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); } if (!ModelState.IsValid) { await LoadAsync(user); return Page(); } var email = await _userManager.GetEmailAsync(user); if (Input.NewEmail != email) { user.Email = Input.NewEmail; // 必须更新标准化邮箱,否则Identity的邮箱查询、登录等功能会异常 user.NormalizedEmail = _userManager.NormalizeEmail(Input.NewEmail); // 设为邮箱已确认 user.EmailConfirmed = true; var updateResult = await _userManager.UpdateAsync(user); if (!updateResult.Succeeded) { foreach (var error in updateResult.Errors) { ModelState.AddModelError(string.Empty, error.Description); } await LoadAsync(user); return Page(); } StatusMessage = "邮箱已修改成功"; return RedirectToPage(); } StatusMessage = "邮箱未发生变更"; return RedirectToPage(); }
注意事项
如果你的业务逻辑中存在依赖EmailConfirmed字段的判断,需要根据自身需求调整该字段的赋值。
内容的提问来源于stack exchange,提问作者Krellex
相关产品推荐
相关产品推荐

