为什么ResetPasswordAsync不起作用?

Ric*_*chC 14 asp.net-mvc asp.net-identity

当我拨打下面的代码时,我总是得到 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();
        }
Run Code Online (Sandbox Code Playgroud)

user.Id和Password的值有效.结果错误总是说"无效令牌",我没有看到它,因为我得到它并立即检查它和它的错误.这只是一个健全性测试 - 我通常通过电子邮件将令牌发送给用户,但这也无效.

更新1 我在同一个控制器中定义UserManager,如下所示:

    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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

更新2 这是我的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;
    }
}
Run Code Online (Sandbox Code Playgroud)

Joã*_*elo 25

这是一个很长的镜头,但如果您UserManager声明它支持用户安全标记,那么请确保在数据库级别用户具有有效的安全标记,更具体地说,它必须没有NULL标记.

原因是在生成代码时,如果标记出现,null那么它将被string.Empty生成的重置代码替换并用于生成的重置代码.但是,在验证重置代码时,来自它的标记将直接与来自数据库的标记进行比较,因此您可能最终string.Emptynull与验证进行比较并导致验证失败.

来自ASP .NET Identity 2.2的源代码DataProtectorTokenProvider(在以前的版本中是相同的):

// 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
}
Run Code Online (Sandbox Code Playgroud)

  • 我的安全性戳并非为null,但仍然无法正常工作,是否还有其他线索可以说明为什么会发生这种情况?谢谢。 (3认同)