我正在开发一个MVC5 ASP.Net应用程序
我正在使用Identity 2.2.0进行身份验证
一切都很好,但由于Invalid Token
错误,我无法重设密码
以下是ResetPassword
控制器中的Account
相关操作。
[AllowAnonymous]
public ActionResult ForgotPassword()
{
return View();
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (!ModelState.IsValid) return View(model);
ApplicationUser userModel = await UserManager.FindByNameAsync(model.Email);
if (userModel == null)
ModelState.AddModelError("", "The user doesn't exist");
if (userModel != null && !await UserManager.IsEmailConfirmedAsync(userModel.Id))
ModelState.AddModelError("", "The user email isn't confirmed");
if (!ModelState.IsValid) return View();
var user = _userService.GetUserByEmail(model.Email);
// 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
string websiteTitle = StaticAssests.WebsiteTitle;
string emailContext = _settingService.GetValue(SettingNames.ResetPasswordMailFormat);
string code = await UserManager.GeneratePasswordResetTokenAsync(userModel.Id);
string callbackUrl = Url.Action("ResetPassword", "Account", new { userId = userModel.Id, code }, Request.Url.Scheme);
emailContext = emailContext.Replace("{userfullname}", user.FullName);
emailContext = emailContext.Replace("{websitetitle}", websiteTitle);
emailContext = emailContext.Replace("{websitedomain}", StaticVariables.WebsiteDomain);
emailContext = emailContext.Replace("{username}", userModel.UserName);
emailContext = emailContext.Replace("{resetpasswordurl}", callbackUrl);
emailContext = emailContext.Replace("{date}", new PersianDateTime(DateTime.Now).ToLongDateTimeString());
await UserManager.SendEmailAsync(userModel.Id, string.Format("Reset password {0}", websiteTitle), emailContext);
return RedirectToAction("ForgotPasswordConfirmation", "Account");
}
[AllowAnonymous]
public ActionResult ForgotPasswordConfirmation()
{
return View();
}
[AllowAnonymous]
public ActionResult ResetPassword(string code)
{
return code == null ? View("Error") : View();
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ResetPassword(ResetPasswordViewModel model)
{
if (!ModelState.IsValid) return View(model);
ApplicationUser userModel = await UserManager.FindByNameAsync(model.Email);
if (userModel == null)
{
ModelState.AddModelError("", "The user doesn't exist");
return View();
}
// Invalid Token error
IdentityResult result = await UserManager.ResetPasswordAsync(userModel.Id, model.Code, model.Password);
if (result.Succeeded)
{
return RedirectToAction("ResetPasswordConfirmation", "Account");
}
AddErrors(result);
return View();
}
我检查了以下内容:
1.重置电子邮件发送成功。
2. GeneratePasswordResetTokenAsync
运行没有任何问题。并且生成的代码与code
动作中的ResetPassword
参数相同。
IdentityConfig:
public class ApplicationUserManager : UserManager<ApplicationUser, int>
{
public ApplicationUserManager(IUserStore<ApplicationUser, int> userStore) : base(userStore)
{
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
ApplicationUserManager applicationUserManager = new ApplicationUserManager(new ApplicationUserStore());
//ApplicationUserManager applicationUserManager = new ApplicationUserManager(context.Get<ApplicationUser>());
//new ApplicationUserManager(new UserStore<UserModel>(context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
//applicationUserManager.UserValidator = new UserValidator<UserIdentityModel, int>(applicationUserManager)
//{
// AllowOnlyAlphanumericUserNames = false,
// RequireUniqueEmail = true,
//};
applicationUserManager.PasswordValidator = new MyMinimumLengthValidator(6);
applicationUserManager.UserValidator = new MyUserModelValidator();
applicationUserManager.PasswordHasher = new MyPasswordHasher();
// Configure user lockout defaults
applicationUserManager.UserLockoutEnabledByDefault = true;
applicationUserManager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
applicationUserManager.MaxFailedAccessAttemptsBeforeLockout = 5;
// Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user
// You can write your own provider and plug in here.
applicationUserManager.RegisterTwoFactorProvider("PhoneCode",
new PhoneNumberTokenProvider<ApplicationUser, int>
{
MessageFormat = "Your security code is: {0}"
});
applicationUserManager.RegisterTwoFactorProvider("EmailCode",
new EmailTokenProvider<ApplicationUser, int>
{
Subject = "Security code",
BodyFormat = "your security code is {0}"
});
applicationUserManager.EmailService = new EmailService();
applicationUserManager.SmsService = new SmsService();
IDataProtectionProvider dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
applicationUserManager.UserTokenProvider =
new DataProtectorTokenProvider<ApplicationUser, int>(dataProtectionProvider.Create("ASP.NET Identity"));
}
return applicationUserManager;
}
}
怎么了?
更新
我已将User Id
从字符串更改为int。
答案 0 :(得分:3)
我知道这是一个老问题,但我在两个项目中遇到过这个问题,两次问题完全相同。也许这个答案可能对其他人有帮传递的令牌包含不能在URL字符串中使用而不会导致问题的特殊字符。
将令牌传递给前端UI时,请务必对令牌进行URLEncode,如下所示:
var callbackUrl =
new Uri(string.Format("{0}/resetpassword?userId={1}&code={2}",
ConfigurationManager.AppSettings["websiteUrl"], user.Id,
WebUtility.UrlEncode(token)));
当令牌传回后端时,在将令牌传递给密码ResetPassword函数之前解码令牌:
var result = await this.AppUserManager.ResetPasswordAsync(appUser.Id, WebUtility.UrlDecode(resetPasswordBindingModel.ConfirmCode),
resetPasswordBindingModel.NewPassword);
我遇到此问题的两个项目都在前端运行HTML / MVC / JavaScript,并且验证是通过ASP.NET WebAPI 2.x完成的。
另一个注意事项:由于某些原因,UrlDecode无法正确解码加号,您会在令牌中获得空格而不是&#39; +&#39;。我使用的技巧是使用字符串替换将任何空格转换为+符号。它并不理想,但我没有遇到任何问题。