asp.net-mvcasp.net-web-apiknockout.jsasp.net-identityreset-password

Forgot Password with asp.net identity


In my MVC and web API projects I'm using ASP.NET Identity for the Login.

This is my Forgot Password function on the AccountController:

[HttpPost]
[AllowAnonymous]
[Route("ForgotPassword")]
public async Task<IHttpActionResult> ForgotPassword(ForgotPasswordViewModel model) 
{
    if (ModelState.IsValid) 
    {
        var user = await UserManager.FindByNameAsync(model.Email);

        if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id))) 
            return Ok();

        try 
        {
            var code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
            
            var callbackUrl = new Uri(@ "http://MyProject/ResetPassword?userid=" + user.Id + "&code=" + code);

            string subject = "Reset Password";
            string body = "Please reset your password by clicking <a href=\"" + callbackUrl + "\">here</a>";
            SendEmail(user.Email, callbackUrl, subject, body);
        } 
        catch (Exception ex) 
            throw new Exception(ex.ToString());

        return Ok();
    }

    // If we got this far, something failed, redisplay form
    return BadRequest(ModelState);
}

I'm getting the confirmation email, I am successfully redirected to the Reset Password View but then I'm not sure how to proceed.

How do I reset a password with the following parameters: NewPssword, ConfirmPassword and Code?

I tried to call the SetPassword method but got a 401 error.

self.resetPassword = function () {
    var data = {
        Email: self.loginUserName(),
        NewPassword: self.registerPassword(),
        ConfirmPassword: self.registerPassword2()
    }
    $.ajax({
        type: 'POST',
        url: '../API/Account/SetPassword',
        contentType: 'application/json; charset=utf-8',
        data: JSON.stringify(data),
        complete: showError
    });
}

And the setPassword function:

// POST api/Account/SetPassword
[Route("SetPassword")]
public async Task<IHttpActionResult> SetPassword(SetPasswordBindingModel model) 
{
    if (!ModelState.IsValid) 
        return BadRequest(ModelState);

    IdentityResult result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword);

    if (!result.Succeeded) 
        return GetErrorResult(result);

    return Ok();
}

Currently the process is a s follow:

  1. user clicks on "Forgot Password" link.
  2. He is redirected to the Forgot Password View that has one field: Email.
  3. The user provides his email address and submit the form.
  4. the request is being sent to the Forgot Password function.
  5. An email with a unique code is being sent to the client.

Till here I wrote the code and got it to work but I'm not sure how to implement the next steps:

  1. The user is redirected the the Reset Password View that has 3 fields: Email, New Password and Confirm Password.
  2. The user submits the form, a request is being sent to the SetPassword function (?) with the unique code and the user's password is being reset successfully.

Thanks in advance.


Solution

  • Sounds like your SetPassword api should call

    var user = await UserManager.FindByNameAsync(model.Email);
    if (user != null)
    {
        var result = await UserManager.ResetPasswordAsync(user.Id, model.Code, model.NewPassword);
        if (result.Succeeded)
        {
              //handle success
        }
    }
    //handle invalid