ASP.NET Core Identity - Allow Password Reset
In the previous two article (Part
1 and Part 2)
you learnt to implement the ASP.NET Core identity in your web applications and
also to add email verification support. In this article you will learn to enable
password reset so that users can reset their passwords and specify a new
password.
The password reset step in ASP.NET Core Identity works as follows:
- A user indicates that he wants to reset his password. He does so by
specifying his UserName.
- The system then generates a password reset token (just like the email
verification token you used in the previous part)
- The system sends an email to the user along with a link to reset the
password. This link contains the password reset token.
- The user clicks on the password reset link and is presented with a form
wherein new password can be supplied.
- The system resets the password after validating the token and then
assigns the new password to the user.
To implement password reset, you need to add a view model class and a couple
of views. Let's begin.
Open the Login view and modify it to include another form for resetting the
password. The following markup shows the new form.
<h1>Reset Your Password</h1>
<form asp-controller="Account"
asp-action="SendPasswordResetLink"
method="post">
<table>
<tr>
<td><label asp-for="UserName">User Name :
</label></td>
<td><input name="UserName" type="text" /></td>
</tr>
<tr>
<td colspan="2">
<input type="submit"
value="Reset Password" />
</td>
</tr>
</table>
<strong>@ViewBag.Message</strong>
<div asp-validation-summary="All"></div>
</form>
Notice that the above form contains textbox for entering user name and
submits to the SendPasswordResetLink() action. The following figure shows how
the above form looks like in the browser:

The SendPasswordResetLink() action is shown below:
public IActionResult SendPasswordResetLink(string username)
{
MyIdentityUser user = userManager.
FindByNameAsync(username).Result;
if (user == null || !(userManager.
IsEmailConfirmedAsync(user).Result))
{
ViewBag.Message = "Error while
resetting your password!";
return View("Error");
}
var token = userManager.
GeneratePasswordResetTokenAsync(user).Result;
var resetLink = Url.Action("ResetPassword",
"Account", new { token = token },
protocol: HttpContext.Request.Scheme);
// code to email the above link
// see the earlier article
ViewBag.Message = "Password reset link has
been sent to your email address!";
return View("Login");
}
The SendPasswordResetLink() action receives the username as entered by the
user on the Login view. It then generates a password reset token using
GeneratePasswordResetTokenAsync() method of the UserManager. The
GeneratePasswordResetTokenAsync() method accepts a MyIdentityUser object whose
password is to be reset.
Then a URL is generated containing the password reset token in the query
string. The URL points to the ResetPassword() action (discussed next). Note that
the code that actually sends an email has been omitted for the sake of clarity.
A sample URL looks like this:
http://localhost:49310/Account/ResetPassword?token=....
Before you develop the ResetPassword() actions and the ResetPassword view,
add new view model class - ResetPasswordViewModel - in the Models folder. This
class is shown below:
public class ResetPasswordViewModel
{
[Required]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
[Required]
[DataType(DataType.Password)]
public string ConfirmPassword { get; set; }
[Required]
public string Token { get; set; }
}
The ResetPasswordViewModel contains four properties - UserName, Password,
ConfirmPassword and Token. The Token property holds the password rest token
generated earlier.
The ResetPassword() GET action displays ResetPassword view for supplying the
new password.
public IActionResult ResetPassword(string token)
{
return View();
}
The markup of ResetPassword view is as follows:
@model ResetPasswordViewModel
...
...
<h1>Reset Your Password</h1>
<form asp-controller="Account"
asp-action="ResetPassword"
method="post">
<input type="hidden" asp-for="Token" />
<table>
<tr>
<td><label asp-for="UserName"></label></td>
<td><input asp-for="UserName" /></td>
</tr>
<tr>
<td><label asp-for="Password">
New Password</label></td>
<td><input asp-for="Password" /></td>
</tr>
<tr>
<td><label asp-for="ConfirmPassword">
Confirm New Password</label></td>
<td><input asp-for="ConfirmPassword" /></td>
</tr>
<tr>
<td colspan="2">
<input type="submit"
value="Reset Password" />
</td>
</tr>
</table>
<div asp-validation-summary="All"></div>
</form>
A sample run of the PasswordReset view looks like this:

The ResetPassword view POSTs to ResetPassword() POST action. This action is
shown below:
[HttpPost]
public IActionResult ResetPassword
(ResetPasswordViewModel obj)
{
MyIdentityUser user = userManager.
FindByNameAsync(obj.UserName).Result;
IdentityResult result = userManager.ResetPasswordAsync
(user, obj.Token,obj.Password).Result;
if (result.Succeeded)
{
ViewBag.Message = "Password reset successful!";
return View("Success");
}
else
{
ViewBag.Message = "Error while resetting the password!";
return View("Error");
}
}
The ResetPassword() POST action receives ResetPasswordViewModel object
containing user name, new password and the password reset token. It then calls
ResetPasswordAsync() method of UserManager in an attempt to reset the user's
password to the new value. If all goes well the IdentityResult will be
Succeeded. Accordingly a success message or an error message is displayed to the
user.
That's it for now! Keep coding!!