.Net Core Entity Framework 电子邮件确认“单击此处”链接不更新“EmailConfirmed”数据库属性
Posted
技术标签:
【中文标题】.Net Core Entity Framework 电子邮件确认“单击此处”链接不更新“EmailConfirmed”数据库属性【英文标题】:.Net Core Entity Framework Email Confirmation 'Click Here' link does not update 'EmailConfirmed' DB property 【发布时间】:2021-08-29 20:14:33 【问题描述】:我已按照此处 Microsoft 的说明在我的 .Net 5.0 应用中为我的用户注册电子邮件确认设置了 SendGrid:http://go.microsoft.com/fwlink/?LinkID=532713
在用户单击注册确认电子邮件中的确认链接之前,一切正常。
这个问题是由我的确认链接中的杂散放大器引起的。我正在尝试了解它的来源以及如何删除它。
当新用户在Register.cshtml
页面上单击“提交”时,他们会成功定向到RegisterConfirmation.cshtml
页面,并且电子邮件会在他们的收件箱中收到。
实际行为:
用户单击电子邮件中的链接并点击ConfirmEmail
页面。
用户被重定向到/Index
页面。
数据库中的EmailConfirmed
bool 未更新。
如果我在控制器中注释掉到 /Index 的重定向,则会收到如下所示的空值错误。
//if (userId == null || code == null)
//
// return RedirectToPage("/Index", new culture );
//
但是,查询选项卡显示 userId 和 code 是正确的。
预期行为:
用户点击电子邮件中的链接。
数据库中的EmailConfirmed
布尔值IS已更新。
用户看到带有成功消息的ConfirmEmail
页面。
ConfirmEmail.cshtml.cs
using System;
snip...
namespace MyApp.Areas.Identity.Pages.Account
[AllowAnonymous]
public class ConfirmEmailModel : PageModel
private readonly UserManager<ApplicationUser> _userManager;
private readonly ISharedCultureLocalizer _loc;
private readonly string culture;
readonly ConfirmEmailPageLocSourceNames _locSourceConfirmEmailPageNameReferenceLibrary = new ConfirmEmailPageLocSourceNames();
readonly SharedCrossPageLocSourceNames _locSourceSharedCrossPageNameReferenceLibrary = new SharedCrossPageLocSourceNames();
public ConfirmEmailModel(UserManager<ApplicationUser> userManager, ISharedCultureLocalizer loc)
_userManager = userManager;
_loc = loc;
culture = System.Globalization.CultureInfo.CurrentCulture.Name;
[TempData]
public string StatusMessage get; set;
snip...
public async Task<IActionResult> OnGetAsync(string userId, string code)
snip...
if (userId == null || code == null)
return RedirectToPage("/Index", new culture );
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
var msg = _loc.GetLocalizedString("Unable to load user with ID '0'.", userId);
return NotFound(msg);
code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code));
var result = await _userManager.ConfirmEmailAsync(user, code);
if (result.Succeeded)
var msg = _loc.GetLocalizedString("Thank you for confirming your email.");
TempData.Success(msg);
else
var msg = _loc.GetLocalizedString("Error confirming your email.");
TempData.Danger(msg);
return Page();
RegisterConfirmation.cshtml.cs
using Microsoft.AspNetCore.Authorization;
snip...
namespace MyApp.Areas.Identity.Pages.Account
[AllowAnonymous]
public class RegisterConfirmationModel : PageModel
private readonly UserManager<ApplicationUser> _userManager;
private readonly IEmailSender _sender;
readonly RegisterConfPageLocSourceNames _locSourceRegisterConfPageNameReferenceLibrary = new RegisterConfPageLocSourceNames();
readonly SharedCrossPageLocSourceNames _locSourceSharedCrossPageNameReferenceLibrary = new SharedCrossPageLocSourceNames();
public RegisterConfirmationModel(UserManager<ApplicationUser> userManager, IEmailSender sender)
_userManager = userManager;
_sender = sender;
public string Email get; set;
snip...
public async Task<IActionResult> OnGetAsync(string email)
PageTabTitle = _locSourceRegisterConfPageNameReferenceLibrary.GetLocSourcePageTabTitleNameReferenceForRegisterConfPage();
snip...
if (email == null)
return RedirectToPage("/Index");
var user = await _userManager.FindByEmailAsync(email);
if (user == null)
return NotFound($"Unable to load user with email 'email'.");
Email = email;
return Page();
Register.cshtml.cs
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
Debug.WriteLine("**************** " + code);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
Debug.WriteLine("**************** 1 *** " + code);
var callbackUrl = Url.Page("/Account/ConfirmEmail", pageHandler: null, values: new area = "Identity", userId = user.Id, code = code, culture , protocol: Request.Scheme);
var mailHeader = _loc.GetLocalizedString("Confirm your GatheringForGood email");
var mailBody = _loc.GetLocalizedString(CultureInfo.CurrentCulture.Name, "Please confirm your GatheringForGood account by <a href='0'>clicking here</a>.", HtmlEncoder.Default.Encode(callbackUrl));
await _emailSender.SendEmailAsync(Input.Email, mailHeader, mailBody);
EmailSender.cs 中的函数
public Task SendEmailAsync(string email, string subject, string message)
return Execute(Options.SendGridKey, subject, message, email);
public Task Execute(string apiKey, string subject, string message, string email)
var client = new SendGridClient(apiKey);
var msg = new SendGridMessage()
From = new EmailAddress("info@myemail.com", Options.SendGridUser),
Subject = subject,
PlainTextContent = message,
HtmlContent = message
;
msg.AddTo(new EmailAddress(email));
// Disable click tracking.
// See https://sendgrid.com/docs/User_Guide/Settings/tracking.html
msg.SetClickTracking(false, false);
return client.SendEmailAsync(msg);
更新:
在我的日志中的回调字符串中显示
userId=362c17ae-7854-42fb-91c3-efb19cc875f2&code=
但在 gmail 中收到的链接显示
userId=362c17ae-7854-42fb-91c3-efb19cc875f2&code=
在 Postman 中测试,这绝对是问题所在。我需要电子邮件正文中的链接看起来像这样。注意没有放大器;
https://localhost:44305/en/Identity/Account/ConfirmEmail?userId=d62d4727-f6ce-493c-bcf3-eb85a50a914f&code=Q2ZESjhKbkE2NU5BVk85S2drRnMvV3VtZXBySVFlTHZrQlNvUU9xbUxrYWQ5NjFDV0NvZGY1eHVCK01SSHVIL3EwMjEwYk8rU1lLaHJ4UHF1VS84RjJQTThBWlY4VHZTcGcrQVpiZU9wWHFyWnlsVkFpSFVUV3lIMGJjaG14aFJKQkgxNjZoQkVNM3ZETnR2WHhoZmx0ZnhQR095azdDREJVZVdJN01CTTRCcFptejJvSURjNHloZHdxRDl0UCs0eEdic1NMK25wbnFqb0xhdHFoR3M3T3BkTElhbG5TVU9obTJaTFpvc0xUb0RINzM2UmFBTVlrakZWL2VsV0YvUEJSaE1HQT09
【问题讨论】:
您必须编写代码来进行更新。 Stack Overflow 不存在为您执行此操作。 该评论显然没有帮助。我按照 Microsoft 的标识框架电子邮件确认说明进行操作,但它不起作用。我试过自己弄清楚,但我很难过。 “实体框架”搭建的身份页面。 @DMur - 你永远不会表明你正在使用实体框架UI,其中有很多东西为你搭建了脚手架。在教程中提供第四课(或其他课程)的链接对读者的期望太高了!我认为您的问题是有效的,但值得重写...&amp;
在 html 中通常非常好。发生这种情况是因为您在 Register.cshtml
的 url 上调用了 HtmlEncoder.Default.Encode..
。
【参考方案1】:
看起来有值的变量是amp;code; 不是代码。你有没有机会在某个地方有 2 个 & 符号?是的 -
b3a&code=Q2ZE
找出您的代码在确认电子邮件中生成此类错误链接的原因
【讨论】:
【参考方案2】:生成的链接似乎也在确认 URL 中查询字符串参数之间的&
编码:
// This is the problem
...&code=Q2ZESjhKb...
//it should be lilke below
...&code=Q2ZESjhKb...
【讨论】:
链接生成代码中没有与号。上面的更新 2。 您可以在callback
字符串中找到它
Hmmm... 在我日志中的回调字符串中显示 userId=362c17ae-7854-42fb-91c3-efb19cc875f2&code= 但在 gmail 中收到的链接中显示 userId=362c17ae-7854-42fb- 91c3-efb19cc875f2&code=
检查电子邮件发送中间件(是SendGrid吗?),应该有一些选项可以对电子邮件正文进行编码或将其格式定义为html。
虽然我不知道我的日志中的 & 来自哪里。 userId 值的末尾没有 & 符号。也许它应该只是 875f2code=【参考方案3】:
已修复! 最后我只需要从我的 mailBody 字符串中删除 Html 编码。
我换了:
var mailBody = _loc.GetLocalizedString(CultureInfo.CurrentCulture.Name, "Please confirm your GatheringForGood account by <a href='0'>clicking here</a>.", HtmlEncoder.Default.Encode(callbackUrl));
与:
var mailBody = _loc.GetLocalizedString(CultureInfo.CurrentCulture.Name, "Please confirm your GatheringForGood account by <a href='" + callbackUrl + "'>clicking here</a>.");
感谢您的所有帮助。
【讨论】:
以上是关于.Net Core Entity Framework 电子邮件确认“单击此处”链接不更新“EmailConfirmed”数据库属性的主要内容,如果未能解决你的问题,请参考以下文章
C# ASP.NET Core Entity Framework Core 异步 ToQueryable 比较
根据 ASP.NET Core 和 Entity Framework Core 中的条件禁用 [必需] 属性
ASP.NET Core 和 Entity Framework Core:Linq 中的左(外)连接
dotnet跨平台微软昨天宣布正式发布.NET Core RC2和.NET Core SDK Preview 1,还有Entity Framework Core RC2