ASP.net Identity v2.0.0电子邮件确认/重置密码错误

本文关键字:密码 错误 电子邮件 net Identity v2 ASP 确认 | 更新日期: 2023-09-27 18:26:44

我们6天前刚刚推出ASP.net MVC(使用Identity 2.0)web应用程序,已有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-标识2-无效令牌错误,中途)的答案

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

但对于所有OWIN的东西来说,这已经不再是必要的了,对吧?

这真的是问题所在吗?如果是的话,那ASP.net Identity团队到底是什么?为什么?

我改变了一些事情:

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

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;
    }

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

然后我唯一能想到的就是我是如何添加数据库类的,但这不应该影响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来找我们的,我想他们只是在使用苹果的默认邮件客户端,但不是肯定的。我不知道有任何垃圾邮件过滤器或电子邮件设置会从链接中删除查询字符串值。

当我试图启动一个伟大的新创业公司时,我有点迫切需要答案,但却被ASP.net身份技术或漏洞或其他问题所困扰。

关于在哪里查找或如何设置的建议将不胜感激

ASP.net Identity v2.0.0电子邮件确认/重置密码错误

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

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

如果我能证实这一点,这是另一件需要注意的事情。

我最终在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页面。

这不是一个很好的解决方案,但我一直找不到任何东西来解决这个问题。