Why is ResetPasswordAsync not working?

When I call the code below, I always get result.Succeeded = false

  [HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> ResetPassword(ResetPasswordViewModel model) { if (!ModelState.IsValid) { return View(model); } var user = await UserManager.FindByNameAsync(model.Email); if (user == null) { // Don't reveal that the user does not exist return RedirectToAction("ResetPasswordConfirmation", "Account"); } string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id); var result = await UserManager.ResetPasswordAsync(user.Id, code, model.Password); //var result = await UserManager.ResetPasswordAsync(user.Id, model.Code, model.Password); if (result.Succeeded) { return RedirectToAction("ResetPasswordConfirmation", "Account"); } AddErrors(result); return View(); } 

Values ​​for user.Id and Password are valid. Errors of the result always say “Invalid token”, which I do not see as much as possible, since I receive it and immediately check it, and these are errors. This is just a sanity test - I usually send the token via email to the user, but that doesn't work either.

UPDATE 1 I am defining a UserManager in the same controller as this:

  private ApplicationSignInManager _signInManager; private ApplicationUserManager _userManager; public AccessController() { } public AccessController(ApplicationUserManager userManager, ApplicationSignInManager signInManager) { UserManager = userManager; SignInManager = signInManager; } public ApplicationSignInManager SignInManager { get { return _signInManager ?? HttpContext.GetOwinContext().Get<ApplicationSignInManager>(); } private set { _signInManager = value; } } public ApplicationUserManager UserManager { get { return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>(); } private set { _userManager = value; } } 

UPDATE 2 Here is my ApplicationUserManager code:

 public class ApplicationUserManager : UserManager<ApplicationUser> { public ApplicationUserManager(IUserStore<ApplicationUser> store) : base(store) { } public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context) { var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>())); // Configure validation logic for usernames manager.UserValidator = new UserValidator<ApplicationUser>(manager) { AllowOnlyAlphanumericUserNames = false, RequireUniqueEmail = true }; // Configure validation logic for passwords manager.PasswordValidator = new PasswordValidator { RequiredLength = 6, RequireNonLetterOrDigit = true, RequireDigit = true, RequireLowercase = true, RequireUppercase = true, }; // Configure user lockout defaults manager.UserLockoutEnabledByDefault = true; manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5); manager.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 it in here. manager.RegisterTwoFactorProvider("Phone Code", new PhoneNumberTokenProvider<ApplicationUser> { MessageFormat = "Your security code is {0}" }); manager.RegisterTwoFactorProvider("Email Code", new EmailTokenProvider<ApplicationUser> { Subject = "Security Code", BodyFormat = "Your security code is {0}" }); manager.EmailService = new EmailService(); manager.SmsService = new SmsService(); var dataProtectionProvider = options.DataProtectionProvider; if (dataProtectionProvider != null) { manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity")); } return manager; } } 
+8
asp.net-mvc asp.net-identity
source share
1 answer

This is a long shot, but if your UserManager claims that it supports user security labels, then make sure that the user has a valid security label at the database level, or rather, it should not have a NULL stamp.

The reason is that when generating the code, if the stamp comes as NULL , then it is replaced by string.Empty and is used in the generated reset code. However, when checking the reset code, the stamp coming from it will be compared directly with what comes from the database, so you can compare string.Empty with NULL and, as a result, do not check the validation.

From the ASP.NET Identity 2.2 source code for the DataProtectorTokenProvider (in the previous version it was the same):

 // GenerateAsync method if (manager.SupportsUserSecurityStamp) { stamp = await manager.GetSecurityStampAsync(user.Id); } writer.Write(stamp ?? ""); // Written as "" if null // ValidateAsync method if (manager.SupportsUserSecurityStamp) { var expectedStamp = await manager.GetSecurityStampAsync(user.Id).WithCurrentCulture(); return stamp == expectedStamp; // Read as "" but compared directly to null } 
+19
source share

All Articles