Matthias Burger
Matthias Burger

Reputation: 5946

Asp .net core changing password requires application restart

I'm starting my application, logging in and change my password (I'm using the default net .core identity):

IdentityResult identityResult = 
                await _userManager.ChangePasswordAsync(
                     applicationUser, 
                     model.CurrentPassword, 
                     model.NewPassword);

this works and in the database the new hashed password is stored.

Then, I'm logging out and try to login with the new password. But

if (await _userManager.CheckPasswordAsync(user, password))

return false. (Logging in with the old password still works, and I'm not caching anything)

When I'm restarting my application and trying to login with the new password, it works. I guess it's somewhere a problem with that PasswordStore (is there a caching?)? Any other suggestions what I may have forgotten or why this doesn't work?

edit:

the complete change password method:

[HttpPut]
[Route("api/user/changepassword/{ident}")]
public async Task<bool> ChangePassword(int ident, [FromBody]ChangePasswordModel model)
{
    if (!ModelState.IsValid)
        return false;

    ApplicationUser applicationUser;

    if ((applicationUser = await _userManager.FindByIdAsync(ident.ToString())) == null)
        return false;

    IdentityResult identityResult = await _userManager.ChangePasswordAsync(applicationUser, model.CurrentPassword, model.NewPassword);
    return identityResult.Succeeded;
}

part from my startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddIdentity<ApplicationUser, ApplicationRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

Upvotes: 2

Views: 1987

Answers (1)

Matthias Burger
Matthias Burger

Reputation: 5946

So I guess, the AspNetCores UserManager<TUser> caches data (and I guess it's cached by the PasswordStore? Please correct me, if wrong.)

I could fix it by getting a new UserManager<TUser>-object when validating the password in the tokenprovider-middleware.

private async Task _generateToken(HttpContext context)
{
    StringValues username = context.Request.Form["username"];
    StringValues password = context.Request.Form["password"];

    var usermanager = context.RequestServices.GetRequiredService<UserManager<ApplicationUser>>();

    ApplicationUser user = await usermanager.FindByNameAsync(username);

    if (user == null)
    {
        context.Response.StatusCode = StatusCodes.Status400BadRequest;
        await context.Response.WriteAsync("Invalid username or password.");
        return;
    }

    ClaimsIdentity identity = await _getIdentity(user, password);

    if (identity == null)
    {
        await usermanager.AccessFailedAsync(user);

        context.Response.StatusCode = StatusCodes.Status400BadRequest;
        await context.Response.WriteAsync("Invalid username or password.");
        return;
    }

I can create a new UserManager<TUser> with the following extension-method:

var usermanager = context.RequestServices.GetRequiredService<UserManager<TUser>>();

when validating the password we now validate the new data and the new password is correct (and the previous password is incorrect).

Upvotes: 1

Related Questions