ASP.NET身份2电子邮件确认无效令牌

时间:2017-01-19 09:29:04

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

我知道,这个问题在SO中被多次询问过,但我的问题有点不同。

我遇到GenerateEmailConfirmationTokenAsyncConfirmEmailAsync方法的奇怪问题。

在发送电子邮件之前,我正在使用HttpUtility.UrlEncodeHttpUtility.UrlDecode方法。

奇怪的是,在创建用户和收到邮件之后,我永远无法重现任何错误。但是在相同的环境中,有10个用户报告了无效令牌的问题。

我搜索了一下,我发现它可能由于机器密钥而发生,如果IIS重新启动或某事或发布后可能会更改。所以为了解决这个问题,我已经生成了一个机器密钥并保存在web.config中,但问题仍然存在。

我在Azure App Service中托管此内容。

还有什么其他问题的想法?

更新:我在这里添加代码供您查看

string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);

var callbackUrl = new Uri(string.Format("{0}?userId={1}&code={2}", ConfigurationManager.AppSettings["EmailConfirmationURL"], user.Id, HttpUtility.UrlEncode(code)));

string emailTemplate = MailTemplates.UserRegistrationEmailTemplate(FirstName, CompanyName, callbackUrl);

await CustomEmail.SendEmail(new List<string> { user.Email }, "Confirm your account", emailTemplate);

确认工作为

IdentityResult result = await UserManager.ConfirmEmailAsync(userId, HttpUtility.UrlDecode(code));

2 个答案:

答案 0 :(得分:0)

一个可能的原因可能是,如果用户花费太长时间提交令牌,则令牌在验证之前到期。令牌具有生命周期,在它们失效之前必须使用它们。默认TokenLifespanis一天(24小时)。

检查身份配置代码,以查看您对令牌生命周期所做的任何更改。

例如,以下代码将令牌设置为在3小时后过期

if (dataProtectionProvider != null)
{
    manager.UserTokenProvider =
       new DataProtectorTokenProvider<ApplicationUser>
          (dataProtectionProvider.Create("ASP.NET Identity"))
          {                    
             TokenLifespan = TimeSpan.FromHours(3)
          };
}

使用上面的代码,忘记的密码和电子邮件确认令牌将在3小时后过期。在到期后尝试使用令牌的用户将获得无效的令牌错误。

OP表示无法重现该问题。这可能是因为令牌在令牌生命周期内得到验证。

答案 1 :(得分:0)

请使用Url.Action而不是使用字符串连接创建网址。 Url.Action在最新的MVC版本中进行幕后编码,您可以避免编码和解码操作。

以下是您可以使用的代码段。

string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);

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