【问题标题】:ASP.net Identity v2.0.0 Email Confirmation/Reset Password ErrorsASP.net Identity v2.0.0 电子邮件确认/重置密码错误
【发布时间】:2016-03-20 16:12:17
【问题描述】:

我们刚刚在 6 天前推出了我们的 ASP.net MVC(使用 Identity 2.0)网络应用程序,并且已经有超过 5000 人注册了帐户,太棒了!

问题是,点击确认电子邮件链接(重置​​密码似乎也是如此)的用户中有 3-5% 可能会显示错误屏幕,这可能是因为他们的令牌无效。

我在 StackOverflow 上读到,您需要对 url 进行编码以避免特殊字符将其丢弃,然后在验证之前对其进行解码。虽然我这样做没有效果,但一些用户的验证令牌仍然出现错误。

我还了解到,拥有不同的 MachineKey 可能是令牌未被视为有效的原因。一切都托管在 Azure 上,所以我推测(并在 SO 上看到)它已经或应该处理

因此,过去 6 天有 30-50 人向我们发送电子邮件讨论问题,当我试图提出解决方案并将我的 confirmEmail 操作设置为以下时,我感到绝望:

[AllowAnonymous]
        public ActionResult ConfirmEmail(string userId = null, string code = null)
        {
            if (userId == null || code == null)
            {
                return View("Error");
            }
            else
            {
                var emailCode = UserManager.GenerateEmailConfirmationToken(userId);
                var result = UserManager.ConfirmEmail(userId, emailCode);
                return View(result.Succeeded ? "ConfirmEmail" : "Error");
            }   
        }

我心想这不可能失败,它实际上只是生成一个令牌然后立即使用它 - 但不知何故它仍然失败(失败是指用户看到错误页面)

到目前为止,我对可能的解决方案的最佳猜测是来自 SO(Asp.NET - Identity 2 - Invalid Token Error,中途)的答案

每当一个 UserManager 被创建(或 new-ed)时,一个新的 dataProtectionProvider 也会生成。所以当用户收到 电子邮件并单击 AccountController 已经不是的链接 旧的,_userManager 和它的令牌提供者都不是。所以 新的令牌提供者将失败,因为它没有那个令牌 记忆。因此,我们需要为令牌提供者使用单个实例。

但是对于所有 OWIN 的东西,这不再是必需的,对吧?

这真的还是问题吗?如果是这样,那么 ASP.net 身份团队是什么鬼?为什么?

我改变的一些东西:

默认注册操作建议通过以下方式发送确认电子邮件:

var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);

我的注册操作中有以下内容

string callbackUrl = await SendEmailConfirmationTokenAsync(user.Id, "Confirm your XXXXXXX account");

然后我在 SendEmailConfirmationTokenAsync 中指定以下内容

private async Task<string> SendEmailConfirmationTokenAsync(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);

        // construct nice looking email body

            await UserManager.SendEmailAsync(userID, subject, htmlBody);

                return callbackUrl;
    }

对我来说,这两个部分是等价的,不是这样吗?

然后我唯一能想到的另一件事是我如何添加我的 db 类,但这不应该影响 UserManager 吗?

我的帐户控制器的顶部如下所示(这是 MS 提供的示例 + 添加我的数据库的方式):

private readonly SiteClasses db = new SiteClasses();

        public AccountController()
        {
        }

        public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager )
        {
            UserManager = userManager;
            SignInManager = signInManager;
        }

        private ApplicationUserManager _userManager;
        public ApplicationUserManager UserManager
        {
            get
            {
                return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
            }
            private set
            {
                _userManager = value;
            }
        }

    ...

我们正在使用推荐的电子邮件提供商 sendgrid,而我个人从未能够复制此问题(在手动创建了大约 60 个测试帐户之后),而且大多数人似乎相处得很好。

其中一部分可能是用户自己造成的错误,但这似乎发生在一群不精通技术的人身上,他们只是点击链接并期望它像正常的确认电子邮件一样工作。大多数用户都是从他们的 iPhone 来到我们这里的,我认为他们只是在使用 Apple 的默认邮件客户端,但并不积极。我不知道有任何垃圾邮件过滤器或电子邮件设置会从链接中删除查询字符串值。

当我试图启动一家伟大的新创业公司时,我有点急切地想要得到答案,但却被 ASP.net 身份技术或错误或正在发生的任何事情所困扰。

我们将不胜感激有关在哪里查看或如何设置的建议

【问题讨论】:

  • 感谢您花费大量时间来写这个问题。但是你错过了最重要的部分。您没有提到显示的错误。一个单一的堆栈跟踪可能比所有这些细节都更有帮助。
  • 它们没有堆栈跟踪、异常或任何东西。由于我无法弄清楚的原因,它只是一个无效的令牌 - 如果有堆栈跟踪,相信我,它会在这里,如果是这样的话,可能已经自己调试了:)
  • 你好,这里有同样的问题,关于这个线程的任何更新?
  • 我目前正在处理同样的问题。有更新吗?

标签: c# asp.net asp.net-mvc email asp.net-identity


【解决方案1】:

我目前将电子邮件作为 URL 的一部分发送。

我们有一个客户在tufts.edu 有一个转发电子邮件帐户去gmail.com,它必须重写她的电子邮件地址,它是 URL 的一部分——这太可怕了,但我看不出还有什么可能做。

如果我可以确认的话,还有一件事需要注意。

【讨论】:

    【解决方案2】:

    我最终在 AspNetUsers 表中手动确认电子邮件,而不是即时创建新令牌并尝试使用 UserManager.ConfirmEmail。

    [HandleError(ExceptionType = typeof(HttpException), View = "ConfirmEmail")]
    public ActionResult ConfirmEmail(string userId = null, string code = null)
        {
            if (userId == null || code == null)
            {
                return View("Error");
            }
            var result = await UserManager.ConfirmEmailAsync(userId, code);
            if (result.Succeeded)
            {
                return View("ConfirmEmail");
            }
            else
            {
                var user = DBContext.Users.Find(userId);
                user.EmailConfirmed = true;
                DBContext.SaveChanges();
                throw new HttpException(result.Errors.FirstOrDefault());
            } 
    
    
        }
    

    我还使用[HandleError(ExceptionType = typeof(HttpException), View = "ConfirmEmail")] 仍然记录错误,但仍将使用定向到 ConfirmEmail 页面。

    不是一个很好的解决方案,但我找不到任何解决此问题的方法。

    【讨论】:

      猜你喜欢
      • 2020-11-08
      • 1970-01-01
      • 2020-04-11
      • 1970-01-01
      • 2013-06-12
      • 1970-01-01
      • 1970-01-01
      • 2021-04-03
      • 2018-11-02
      相关资源
      最近更新 更多