Forget Password in ASP.NET Identity

How to Implement Forgot Password in ASP.NET Identity:

In this article, I am going to discuss How to Reset a User Password in ASP.NET Identity using Forgot Password. Please read our previous article where we discussed How to Update User Password in ASP.NET Identity.

Reset User Password in ASP.NET Identity using Forget Password:

Let us see the step-by-step process to implement Reset Password in ASP.NET Identity. So, basically, this mechanism is used when the user forgot his password, So, we need to provide one button element with the name Forgot password and when the user clicks on the button it will the Forgot Password screen asks the user to enter the Email Address Something as follow:

Reset User Password in ASP.NET Identity using Forget Password

Once the User Enter the Email address and click on the Email Link, we need to send an email to the above Email Id using which the user can set his new password. After sending the email, we need to give one message something like below saying password reset link send to you email address.

How to Reset a User Password in ASP.NET Identity using Forgot Password

Note: The point that you need to remember is with your Gmail ID and Password you cannot send email because of Security Reasons. In order to send an Email, you need to enable two-factor authentication and then you need to generate the app password instead your original password, you need to use the app password to send the email.

Then the user will receive the Password Reset Email something like the below in his email address.

How to Reset a User Password in ASP.NET Identity using Forgot Password

Once the user clicks on the above link, it will open one page and ask the user to enter the Email, Password, and Confirm Password as shown in the below image.

How to Reset a User Password in ASP.NET Identity using Forgot Password

Once the user provides the valid details and clicks on the Reset button, then the password is going to be reset. Let us proceed and see how we can implement this using ASP.NET Identity.

Creating the Required Action Method:

First, create the following ForgotPassword action method. This action method is going to display the forward password screen to the user.

[AllowAnonymous]
public ActionResult ForgotPassword()
{
    return View();
}

Next, create a class file with the name ForgotPasswordViewModel.cs and then copy and paste the following code into it. This is going to be the Model for our ForgotPassword view.

public class ForgotPasswordViewModel
{
    [Required]
    [EmailAddress]
    [Display(Name = "Email")]
    public string Email { get; set; }
}

Next, add the following ForgotPassword.cshtml view.

@model AspNetIdentityWithNewProject.Models.ForgotPasswordViewModel
@{
    ViewBag.Title = "Forgot your password?";
}

<h2>@ViewBag.Title.</h2>

@using (Html.BeginForm("ForgotPassword", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
    @Html.AntiForgeryToken()
    <h4>Enter your email.</h4>
    <hr />
    @Html.ValidationSummary("", new { @class = "text-danger" })
    <div class="form-group">
        @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" class="btn btn-default" value="Email Link" />
        </div>
    </div>
}

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}
Implementing Send Email Functionality in C#:

Once the user provides the email, then we need to send the password reset email to his Email ID. So, for this create a class file with the name SendEmail.cs and then copy and paste the following code into it. This class has one method which will be used to send the Email to the user’s Email ID.

using System;  
using System.Configuration;  
using System.Net;  
using System.Net.Mail;  
namespace AspNetIdentityWithNewProject.Utility
{
    public class SendEmail
    {
        public static bool EmailSend(string SenderEmail, string Subject, string Message, bool IsBodyHtml = false)
        {
            bool status = false;
            try
            {
                string HostAddress = ConfigurationManager.AppSettings["Host"].ToString();
                string FormEmailId = ConfigurationManager.AppSettings["MailFrom"].ToString();
                string Password = ConfigurationManager.AppSettings["Password"].ToString();
                string Port = ConfigurationManager.AppSettings["Port"].ToString();
                MailMessage mailMessage = new MailMessage();
                mailMessage.From = new MailAddress(FormEmailId);
                mailMessage.Subject = Subject;
                mailMessage.Body = Message;
                mailMessage.IsBodyHtml = IsBodyHtml;
                mailMessage.To.Add(new MailAddress(SenderEmail));
                SmtpClient smtp = new SmtpClient
                {
                    Host = HostAddress,
                    EnableSsl = true
                };
                NetworkCredential networkCredential = new NetworkCredential
                {
                    UserName = mailMessage.From.Address,
                    Password = Password
                };
                smtp.UseDefaultCredentials = false;
                smtp.Credentials = networkCredential;
                smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
                smtp.Port = Convert.ToInt32(Port);
                smtp.Send(mailMessage);
                status = true;
                return status;
            }
            catch (Exception e)
            {
                return status;
            }
        }
    }
}
Modifying the web.config file:

In the EmailSend method, we are fetching the Host, MailFrom, Password, and Port from the Web.config file. So, please include the keys within the appSettings section of your web.config file. Please don’t use your password as it will not work because of the security. Please create an app password and use the app password here.

<add key="Host" value="smtp.gmail.com" />
<add key="Port" value="587" />
<add key="MailFrom" value="YourEmail@gmail.com" />
<add key="Password" value="YourAppPasswoed" />
Creating ForgotPassword HTTPPost Method:

Create the ForgotPassword HTTPPost and then copy and paste the following code into it. In the below code first, we are finding the user by Email which we receive as the input value from the Model. Then we are generating a unique hash value or token using the GeneratePasswordResetTokenAsync method. Then we are creating the callback URL which includes the user ID and the unique token and then we are sending that callback URL or link to the user’s Email Address and we expect the user to click on the same link to reset his password.

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
    if (ModelState.IsValid)
    {
        var user = await UserManager.FindByEmailAsync(model.Email);
        if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
        {
            // Don't reveal that the user does not exist or is not confirmed
            return View("ForgotPasswordConfirmation");
        }

        // For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=320771
        // Send an email with this link
        string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
        var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
        //await UserManager.SendEmailAsync(user.Id, "Reset Password", "Please reset your password by clicking <a href=\"" + callbackUrl + "\">here</a>");

        bool IsSendEmail = SendEmail.EmailSend(model.Email, "Reset Your Password", "Please reset your password by clicking <a href=\"" + callbackUrl + "\">here</a>", true);
        if (IsSendEmail)
        {
            return RedirectToAction("ForgotPasswordConfirmation", "Account");
        }
    }

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

Once the Email is sent, then we are redirecting the user to the password confirmation page and say that the password reset link has been sent to your email address. So, for this, we are creating the following action method.

[AllowAnonymous]
public ActionResult ForgotPasswordConfirmation()
{
    return View();
}

Next, create a view for the above action method with the name ForgotPasswordConfirmation.cshtml and then copy and paste the following HTML code into it.

@{
    ViewBag.Title = "Forgot Password Confirmation";
}

<hgroup class="title">
    <h1>@ViewBag.Title.</h1>
</hgroup>
<div>
    <p>
        Please check your email to reset your password.
    </p>
</div>

Next, create the following ResetPassword method. This is the method that is going to be invoked when the user clicks on the password reset link sent to his email address. If the token or code which we send as part of the callback URL is null, then we are redirecting to the error view else we are opening the Password Reset View.

[AllowAnonymous]
public ActionResult ResetPassword(string code)
{
    return code == null ? View("Error") : View();
}

Next, create the ResetPassword.cshtml view for the above action method and then copy and paste the following code into it.

@model AspNetIdentityWithNewProject.Models.ResetPasswordViewModel
@{
    ViewBag.Title = "Reset password";
}

<h2>@ViewBag.Title.</h2>

@using (Html.BeginForm("ResetPassword", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
    @Html.AntiForgeryToken()
    <h4>Reset your password.</h4>
    <hr />
    @Html.ValidationSummary("", new { @class = "text-danger" })
    @Html.HiddenFor(model => model.Code)
    <div class="form-group">
        @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.PasswordFor(m => m.Password, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" class="btn btn-default" value="Reset" />
        </div>
    </div>
}

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

In the above View, when the user provides the necessary details and clicks on the Reset then the following HTTP Post action method is going to handle the request.

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ResetPassword(ResetPasswordViewModel model)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }
    var user = await UserManager.FindByEmailAsync(model.Email);
    if (user == null)
    {
        // Don't reveal that the user does not exist
        return RedirectToAction("ResetPasswordConfirmation", "Account");
    }
    var result = await UserManager.ResetPasswordAsync(user.Id, model.Code, model.Password);
    //var result =  UserManager.ResetPassword(user.Id, model.Code, model.Password);
    if (result.Succeeded)
    {
        return RedirectToAction("ResetPasswordConfirmation", "Account");
    }
    AddErrors(result);
    return View();
}

In the above code, all necessary information for resetting a user’s password is obtained through an HTTP Post request. This is accomplished by obtaining the user manager from the OWIN context using the GetUserManager method. The FindByEmailAsync method is then used to locate the user to be updated by their ID. If the user cannot be found, an HTTP 404 error page is displayed. However, if the user is located, their password is reset using the ResetPassword method. The success of this action is determined by accessing the Succeeded property of the IdentityResult object. If the operation was not successful, the Errors are looped through and added to the ModelState object with the AddModelError method.

So, this is how we can implement Forgot Password to Reset User Password in ASP.NET Identity.

In the next article, I am going to discuss the Password Policy in ASP.NET Identity. Here, in this article, I try to explain How to Reset a User Password using ASP.NET Identity using Forgot Password Mechanism. I hope you enjoy this How to Reset User Password using in ASP.NET Identity using Forgot Password Mechanism article.

Leave a Reply

Your email address will not be published. Required fields are marked *