2015-03-25 3 views
1

Я разрабатываю приложение ASP.NET MVC5.
Я использую Identity 2.2.0 для аутентификации.
Все в порядке, но я не могу сбросить свой пароль из-за ошибки Invalid Token.
ResetPassword связанные действия в Account контроллер.
Ошибка «Недопустимый токен» при сбросе пароля, ASP.Net Identity 2.2.0

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

Что случилось?

Update:
Я изменил User Id из строки в целое.

ответ

3

Я знаю, что это старый вопрос, но я столкнулся с этим в двух проектах, и оба раза вопрос был тем же самым. Возможно, этот ответ может помочь другим. Передаваемый токен включает специальные символы, которые не могут использоваться как внутри строки URL, не вызывая проблем.

При прохождении маркера переднего конца UI, обязательно URLEncode маркера, что-то вроде этого:

var callbackUrl = 
       new Uri(string.Format("{0}/resetpassword?userId={1}&code={2}", 
        ConfigurationManager.AppSettings["websiteUrl"], user.Id, 
        WebUtility.UrlEncode(token))); 

Когда маркер передается обратно в задний конец, Decode маркера перед передачей его функция пароля ResetPassword:

var result = await this.AppUserManager.ResetPasswordAsync(appUser.Id, WebUtility.UrlDecode(resetPasswordBindingModel.ConfirmCode), 
      resetPasswordBindingModel.NewPassword); 

Оба проекта, где я имел этот вопрос был запущен HTML/MVC/JavaScript на переднем конце и валидация были сделаны над ASP.NET WebAPI 2.x.

Еще одно примечание: UrlDecode по какой-то причине не может правильно декодировать символ плюса, и вы получаете пробел в токене вместо «+». Трюк, который я использовал, - просто использовать замену строки, чтобы преобразовать любые пробелы в знаки +. Это не идеально, но у меня не было проблем с этим.

+0

Спасибо, я проверю его. –

Смежные вопросы