我正在尝试使用asp.net身份验证,我在编码/解码方面遇到一些问题。
用户点击忘记密码链接,所以我们调用:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
[PassModelStateToTempData]
public async Task<ActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (ModelState.IsValid)
{
logger.Info("reset_password attempting for {0}", model.Email);
var user = await UserManager.FindByNameAsync(model.Email);
if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
{
this.Flash("Please check your email, we have sent you instructions on how to reset your password");
return RedirectToAction("ForgotPassword");
}
string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
logger.Debug("forgot_password code {0}", code);
var callbackUrl = Url.Action("ResetPassword", "Session", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
messagingService.ResetPassword(user.Email, callbackUrl);
this.Flash("Please check your email, we have sent you instructions on how to reset your password");
logger.Debug("remind_me successfully send out email to {0} {1}", model.Email, callbackUrl);
return RedirectToAction("ForgotPassword");
}
logger.Info("reset_password failed for {0}", model.Email);
// If we got this far, something failed, redisplay form
return RedirectToAction("ForgotPassword");
}
用户收到电子邮件,然后点击链接,所以我们运行:
[HttpGet]
[AllowAnonymous]
public ActionResult ResetPassword(string code)
{
if (code == null)
{
this.Flash("Invalid login token, please enter your email address again");
return RedirectToAction("ForgotPassword");
}
var vm = new ResetPasswordViewModel
{
Code = code
};
return View(vm);
}
我们将令牌传递给视图-我们要求提供电子邮件和密码,然后用户点击post并运行:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ResetPassword(ResetPasswordViewModel model)
{
if (!ModelState.IsValid)
{
return RedirectToAction("ResetPassword");
}
var user = await UserManager.FindByNameAsync(model.Email);
if (user == null)
{
logger.Info("reset_password user not found [{0}]", model.Email);
// Don't reveal that the user does not exist
return RedirectToAction("ResetPasswordConfirmation", "Session");
}
var result = await UserManager.ResetPasswordAsync(user.Id, model.Code, model.Password);
if (result.Succeeded)
{
return RedirectToAction("ResetPasswordConfirmation", "Session");
}
AddErrors(result);
return RedirectToAction("ResetPassword", new { code = model.Code });
}
由于某些原因,令牌似乎不匹配,这里是我得到的令牌的一个示例-为什么情况不同?
标记:
2015-10-14 13:06:52.7545 | |调试控制器。应用程序|forgot_password代码BoUZZ9OS7rEkKMkEJzerWdds4dZLHFTHO/EkjQC2Zr8YJvCyjsXUKBRLZk8jmAqhjyxOzgqOLdJ8P/ji8y+om2ne7bcsLICzcdLSHzrP6BNEr1/+HKvHcYan+JzAX7Ifpgq7casmMj4f9esAdxejLA==
注意大小写的区别:
2015-10-14 13:07:29.7164 |信息|控制器。应用程序|reset_password尝试使用令牌my.email@gmail.com: bouzz9os7rekkmkejzerwdds4dzlhftho/ekjqc2zr8yjvcyjsxukbrlzk8jmaqhjyxozgqoldj8p/ji8y+om2ne7bcsliczcdlshzrp6bner1/+hkvhcyan+jzax7ifpgq7casmmj4f9esadxejla== ->无效令牌。
您的MVC路由设置为生成小写url:
routes.LowercaseUrls = true;
这意味着你的代码也被转换成小写。可能的解决方案如下:
- 如果可以(或想要)关闭
LowercaseUrls
- 使用MVC属性路由,尽管这可能是一个相当大的切换。
对你来说最简单的选择可能是自己创建URL:
//Generate the URL without the code parameter var callbackUrl = Url.Action( "ResetPassword", "Session", new { userId = user.Id }, protocol: Request.Url.Scheme); //Manually add the code, remembering to encode it callbackUrl = callbackUrl + "&code=" HttpUtility.UrlEncode(code);