2015-02-23 8 views
8

Quando chiamo il codice qui sotto, ho sempre arrivare result.Succeeded = falsePerché ResetPasswordAsync non funziona?

 [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(); 
     } 

I valori per user.Id e Password sono validi. Gli errori di risultato dicono sempre "Token non valido" che non vedo come possibile da quando lo prendo e lo controllo e gli errori immediatamente. Questo è solo un test di sanità mentale: di solito invio il token via e-mail all'utente, ma non funzionava neanche.

UPDATE 1 mi definiscono l'UserManager nello stesso controller in questo modo:

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 Ecco il mio codice ApplicationUserManager:

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; 
    } 
} 
+1

Come si fa a creare istanze di 'UserManager'? Molto probabilmente l'istanza di 'IDataProtectionProvider' viene ricreata e dovrebbe rimanere invariata per convalidare il codice. – trailmax

+0

Hai il set di token AntiForgery nel modulo? Invia il tuo codice modulo – Luca

+0

@Luca Se il token anti-contraffazione non è valido, l'eccezione sarebbe precedente al problema corrente e l'elaborazione non arriverebbe allo stadio di generazione del token. – trailmax

risposta

19

Questo è un colpo lungo, ma se il tuo UserManager afferma che supporta i timbri di sicurezza dell'utente, assicurati che a livello di database l'utente abbia un timbro di sicurezza valido, in particolare, deve non avere un timbro NULL.

Il motivo è che quando si genera il codice, se il timbro viene come null, viene sostituito con string.Empty e utilizzato nel codice di ripristino generato. Tuttavia, durante la convalida del codice di reset, il timbro proveniente da esso verrà confrontato direttamente con quello che viene dal database in modo che si possa finire per confrontare string.Empty a null e in caso contrario la convalida come conseguenza.

da ASP .NET di identità del codice sorgente per 2,2 DataProtectorTokenProvider (era lo stesso della versione precedente):

// 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 
} 
+0

Boom! Era così! SecurityStamp era NULL. Ho messo un guid lì e ha funzionato bene. Non sono del tutto sicuro del motivo per cui è stato NULL, ma ora che ho capito dov'era il problema, posso usare il tuo codice qui sopra e capire perché è stato nullo e come risolverlo in futuro. – EdenMachine

+0

Buon posto! Completamente perso questa opzione! – trailmax

+0

I miei token di ripristino funzionavano in modo strano sul mio sistema di sviluppo ma non sul server di produzione. Questo l'ha risolto. – damccull