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();
}
The values for user.Id and Password are valid. The result errors always say "Invalid Token" which I don't see as possible since I get it and instantly check it and it errors. This is just a sanity test - I normally send the token via email to the user but that wasn't working either.
UPDATE 1 I define the UserManager in the same controller like 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;
}
}
This is a long shot, but if your UserManager
states that it supports user security stamps then make sure that at the database level the user has a valid security stamp, more specifically, it must not have a NULL
stamp.
The reason is that when generating the code, if the stamp comes as null
then it is replaced with string.Empty
and used in the generated reset code. However, when validating the reset code, the stamp coming from it will be compared directly to what comes from the database so you might end up comparing string.Empty
to null
and failing the validation as a consequence.
From ASP .NET Identity 2.2 source code for DataProtectorTokenProvider
(it was the same in previous version):
// 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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With