身份密码重置令牌无效

Posted

技术标签:

【中文标题】身份密码重置令牌无效【英文标题】:Identity password reset token is invalid 【发布时间】:2015-02-21 10:45:45 【问题描述】:

我正在编写 MVC 5 并使用 Identity 2.0。

现在我正在尝试重置密码。但我总是收到重置密码令牌的“无效令牌”错误。

    public class AccountController : Controller

    public UserManager<ApplicationUser> UserManager  get; private set; 

    public AccountController()
        : this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
    
    

我设置了 DataProtectorTokenProvider,

        public AccountController(UserManager<ApplicationUser> userManager)
       
        //usermanager config
        userManager.PasswordValidator = new PasswordValidator  RequiredLength = 5 ;  
        userManager.EmailService = new IddaaWebSite.Controllers.MemberShip.MemberShipComponents.EmailService(); 

        var provider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider();
        userManager.UserTokenProvider = new Microsoft.AspNet.Identity.Owin.DataProtectorTokenProvider<ApplicationUser>(provider.Create("UserToken"))
                                                    as IUserTokenProvider<ApplicationUser, string>;




        UserManager = userManager;

    

我在发送邮件之前生成密码重置

 [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> ManagePassword(ManageUserViewModel model)
    
        if (Request.Form["email"] != null)
        
          var email = Request.Form["email"].ToString();
          var user = UserManager.FindByEmail(email);
          var token = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
           //mail send
        
   

我点击邮件中的链接,我正在获取密码重置令牌并使用

var result = await UserManager.ResetPasswordAsync(model.UserId, model.PasswordToken, model.NewPassword);

结果总是假的,它说“无效令牌”。 我应该在哪里解决?

【问题讨论】:

您将生成的令牌存储在哪里? @vgSefa 在 Identity 中,令牌已签名,这意味着无需将它们存储在某处。 二看:是否生成了token?我认为在设置 UserTokenProvider 时不需要强制转换。也许那里出了点问题。 @Horizo​​n_Net 是的,它生成并尝试移除铸件。还是不行 只是另一个想法:相应用户的电子邮件地址是否已经确认?如here 所述:如果未确认用户电子邮件,该方法会静默失败。如果针对无效电子邮件地址发布错误,恶意用户可以使用该信息找到有效的 userId(电子邮件别名)进行攻击。 好的,谢谢。我添加了电子邮件确认条件。 【参考方案1】:

UserManager.GeneratePasswordResetTokenAsync() 经常返回包含“+”字符的字符串。如果您通过查询字符串传递参数,这就是原因('+' 字符是 URL 中查询字符串中的空格)。

尝试将model.PasswordToken 中的空格字符替换为“+”字符。

【讨论】:

另外,在我的情况下,追加“==”添加令牌的结尾。 或者发送邮件时使用WebUtility.UrlEncode(code),处理表单时使用WebUtility.UrDecode(Model.code) 请注意这个答案:***.com/a/13095475/453142 这是我的情况!! 我也是同样的问题,我无法从代码的最后一端获取“==”,所以如何处理这个我是通过邮件中的查询字符串发送的代码,我也试试这个 WebUtility。邮件中的 UrlEncode(code) 发送和获取时间 WebUtility.UrDecode(Model.code) 使用此但仍然遇到问题并结束获取无效令牌。 我也遇到了编码和解码的问题。它帮助我首先将令牌编码为 Base64,然后在读入时再次对其进行解码。对于字符串的编码/解码,请参阅***.com/questions/11743160/…【参考方案2】:
[HttpPost]
[ValidateAntiForgeryToken]
publicasync Task<ActionResult> ManagePassword(ManageUserViewModel model)

    if (Request.Form["email"] != null)
    
      var email = Request.Form["email"].ToString();
      var user = UserManager.FindByEmail(email);
      var token = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
       //before send mail
      token = HttpUtility.UrlEncode(token);   
  //mail send

    

并在密码重置操作解码令牌HttpUtility.UrlDecode(token);

【讨论】:

不要忘记像这样在重置时解码令牌:var result = await UserManager.ResetPasswordAsync(user.Id, HttpUtility.UrlDecode(code), user.Password); 此编码/解码是我的项目中缺少的部分,因此我通过电子邮件发送的令牌无法正常工作。谢谢!【参考方案3】:

我发现当数据库中 AspNetUsers 表中的用户的 SecurityStamp 列为 NULL 时,也会发生“无效令牌”错误。 使用开箱即用的 MVC 5 Identity 2.0 代码时,SecurityStamp 不会为 NULL,但是在对 AccountController 进行一些自定义时,我们的代码中引入了一个错误,该错误会清除 SecurityStamp 字段中的值。

【讨论】:

启用唯一电子邮件地址强制并且手动插入违反该设置的用户时,更新安全标记可能会失败。【参考方案4】:

这里有很多答案 URLEncode the token before send to get around the fact that the token (a base 64 encoding string) 通常包含“+”字符。解决方案还必须考虑到令牌以 '==' 结尾。

我一直在努力解决这个问题,事实证明,一个大型组织中的许多用户都在使用 Scanmail Trustwave Link Validator(r),它不是对称地编码和解码电子邮件链接中的 URLEncoded 字符串(在撰写本文时)。

最简单的方法是使用 Mateusz Cisek 的答案并发送一个非 URLEncoded 令牌,然后简单地将空格字符替换回 +。在我的例子中,这是在 Angular SPA 中完成的,因此 javascript 变为 $routeParams.token.replace(/ /g,'+')

这里需要注意的是,如果使用 AJAX 发送令牌并滚动您自己的查询字符串解析算法 - 许多示例将每个参数拆分为“=”,这当然不会包括末尾的“==”令牌。使用其中一种正则表达式解决方案或仅查找第一个“=”即可轻松解决。

【讨论】:

以上是关于身份密码重置令牌无效的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 手动生成重置密码令牌:收到错误“此密码重置令牌无效”

Drf令牌认证密码重置

ASP.NET CORE Identity DataProtectionTokenProviderOptions 密码重置令牌无效

ASP.NET Core 2.2 - 密码重置在 Azure 上不起作用(无效令牌)

Rails 4 + 设计:密码重置总是在生产服务器上给出“令牌无效”错误,但在本地工作正常。

如何检查密码重置令牌是不是已过期?