当用户在输入新密码后尝试在重置密码屏幕上重置密码时,我们会收到无效令牌错误消息。 通常这对每个人来说都很好,即使是像#这样的特殊字符。 我们现在有一个案例,有人在重置pw屏幕上输入*他的新密码,只是因为这个特殊字符而得到此错误消息。
我现在已经尝试了几个小时的研究来找到解决方案,为什么会发生这种情况,但没有运气。 我在这里找到了这个解决方案,其中包含用户名中的特殊字符问题,但我们没有这个问题。 密码中只有一个特殊字符存在问题。 由于我们已经在制作中,因此我们不能仅仅在密码中禁止使用该字符。
有人知道了吗?
生成令牌控制器方法:
[HttpPost] [AllowAnonymous] public async Task<ActionResult> ForgotPassword(ForgotPasswordViewModel model) { if (ModelState.IsValid) { var user = await _userManager.FindByNameAsync(model.Email.ToLower()); if (user == null || !(await _userManager.IsEmailConfirmedAsync(user.UserName))) { // Don't reveal that the user does not exist or is not confirmed return View("ForgotPasswordConfirmation"); } // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771 // Send an email with this link var code = await _userManager.GeneratePasswordResetTokenAsync(user.UserName); code = HttpUtility.UrlEncode(code); var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.UserName, code = code }, protocol: Request.Url.Scheme); await _emailService.CreateResetPasswordEmailAsync(user, callbackUrl); return RedirectToAction("ForgotPasswordConfirmation", "Account"); } // If we got this far, something failed, redisplay form return View(model); }重置密码控制器方法:
[HttpPost] [AllowAnonymous] public async Task<ActionResult> ResetPassword(ResetPasswordViewModel model) { if (!ModelState.IsValid) { return View(model); } var user = await _userManager.FindByNameAsync(model.Email.ToLower()); if (user == null) { // Don't reveal that the user does not exist return RedirectToAction("ResetPasswordConfirmation", "Account"); } var result = await _userManager.ResetPasswordAsync(user.UserName, HttpUtility.UrlDecode(model.Code), model.Password); if (result.Succeeded) { return RedirectToAction("ResetPasswordConfirmation", "Account"); } AddErrors(result); return View(); }We get the invalid token error messages when a user tries to reset his password on the reset password screen after entering the new password. Normally this works just fine for everyone even with some special character like #. We have now a case where someone puts in * in his new password on the reset pw screen, gets this error message just because of this special character.
I've tried hours of research now to find a solution to why this happens but with no luck. I've found this solution here which has an issue with special characters in the username but we don't have that issue. There is only an issue with that special character in the password. As we are already in production we can't just disallow that character in passwords.
Someone got a clue?
Generating the token controller method:
[HttpPost] [AllowAnonymous] public async Task<ActionResult> ForgotPassword(ForgotPasswordViewModel model) { if (ModelState.IsValid) { var user = await _userManager.FindByNameAsync(model.Email.ToLower()); if (user == null || !(await _userManager.IsEmailConfirmedAsync(user.UserName))) { // Don't reveal that the user does not exist or is not confirmed return View("ForgotPasswordConfirmation"); } // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771 // Send an email with this link var code = await _userManager.GeneratePasswordResetTokenAsync(user.UserName); code = HttpUtility.UrlEncode(code); var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.UserName, code = code }, protocol: Request.Url.Scheme); await _emailService.CreateResetPasswordEmailAsync(user, callbackUrl); return RedirectToAction("ForgotPasswordConfirmation", "Account"); } // If we got this far, something failed, redisplay form return View(model); }Reset password controller method:
[HttpPost] [AllowAnonymous] public async Task<ActionResult> ResetPassword(ResetPasswordViewModel model) { if (!ModelState.IsValid) { return View(model); } var user = await _userManager.FindByNameAsync(model.Email.ToLower()); if (user == null) { // Don't reveal that the user does not exist return RedirectToAction("ResetPasswordConfirmation", "Account"); } var result = await _userManager.ResetPasswordAsync(user.UserName, HttpUtility.UrlDecode(model.Code), model.Password); if (result.Succeeded) { return RedirectToAction("ResetPasswordConfirmation", "Account"); } AddErrors(result); return View(); }最满意答案
问题是您要对重置令牌进行双重编码。 这里:
var code = await _userManager.GeneratePasswordResetTokenAsync(user.UserName); code = HttpUtility.UrlEncode(code); //<--problem is this line var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.UserName, code = code }, protocol: Request.Url.Scheme);您对令牌进行编码,然后Url.Action将再次执行此操作。 所以解决方案是不要手动编码,让MVC为你处理它 - 只需删除第二行。
另外,在另一端,现在不需要再次解码,所以你的代码将是:
var result = await _userManager.ResetPasswordAsync(user.UserName, model.Code, model.Password);The problem is that you are double encoding the reset token. Here:
var code = await _userManager.GeneratePasswordResetTokenAsync(user.UserName); code = HttpUtility.UrlEncode(code); //<--problem is this line var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.UserName, code = code }, protocol: Request.Url.Scheme);you encode the token and then Url.Action will do it again. So the solution is to not encode manually and let MVC handle it for you - just remove the second line here.
Also, on the other end, there's now no need to decode again, so your code there will be:
var result = await _userManager.ResetPasswordAsync(user.UserName, model.Code, model.Password);更多推荐
发布评论