【问题标题】:.Net Core Entity Framework Email Confirmation 'Click Here' link does not update 'EmailConfirmed' DB property.Net Core Entity Framework 电子邮件确认“单击此处”链接不更新“EmailConfirmed”数据库属性
【发布时间】: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&amp;code=

在 Postman 中测试,这绝对是问题所在。我需要电子邮件正文中的链接看起来像这样。注意没有放大器;

https://localhost:44305/en/Identity/Account/ConfirmEmail?userId=d62d4727-f6ce-493c-bcf3-eb85a50a914f&code=Q2ZESjhKbkE2NU5BVk85S2drRnMvV3VtZXBySVFlTHZrQlNvUU9xbUxrYWQ5NjFDV0NvZGY1eHVCK01SSHVIL3EwMjEwYk8rU1lLaHJ4UHF1VS84RjJQTThBWlY4VHZTcGcrQVpiZU9wWHFyWnlsVkFpSFVUV3lIMGJjaG14aFJKQkgxNjZoQkVNM3ZETnR2WHhoZmx0ZnhQR095azdDREJVZVdJN01CTTRCcFptejJvSURjNHloZHdxRDl0UCs0eEdic1NMK25wbnFqb0xhdHFoR3M3T3BkTElhbG5TVU9obTJaTFpvc0xUb0RINzM2UmFBTVlrakZWL2VsV0YvUEJSaE1HQT09

【问题讨论】:

  • 您必须编写代码来进行更新。 Stack Overflow 不存在为您执行此操作。
  • 该评论显然没有帮助。我按照 Microsoft 的标识框架电子邮件确认说明进行操作,但它不起作用。我试过自己弄清楚,但我很难过。
  • “实体框架”搭建的身份页面。
  • @DMur - 你永远不会表明你正在使用实体框架UI,其中有很多东西为你搭建了脚手架。在教程中提供第四课(或其他课程)的链接对读者的期望太高了!我认为您的问题是有效的,但值得重写...
  • &amp;amp; 在 html 中通常非常好。发生这种情况是因为您在 Register.cshtml 的 url 上调用了 HtmlEncoder.Default.Encode..

标签: asp.net .net asp.net-core asp.net-identity


【解决方案1】:

看起来有值的变量是amp;code; 不是代码。你有没有机会在某个地方有 2 个 & 符号?是的 -

b3a&amp;code=Q2ZE

找出您的代码在确认电子邮件中生成此类错误链接的原因

【讨论】:

    【解决方案2】:

    生成的链接似乎也在确认 URL 中查询字符串参数之间的&amp; 编码:

    // This is the problem
    ...&amp;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>.");
    

    感谢您的所有帮助。

    【讨论】:

      猜你喜欢
      • 2014-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多