Adding forgotten password and password reset mechanisms

Now that you have seen how to add authentication to your applications, you have to think about how you want to help users to reset their forgotten passwords. Users will always forget their passwords, so you need to have some mechanisms in place.

The standard way of handling this type of request is to send an email reset link to the user. The user can then update their password, without the risk of sending the password in clear text through email. Sending a user password directly to a user email is not secure and should be avoided at all costs.

You will now see how to add a reset password feature to the Tic-Tac-Toe application:

  1. Update the login form, and add a new link called Reset Password Here directly after the Sign Up Here link:
        <div class="col-md-12 control"> 
          <div style="border-top: 1px solid#888; padding-top:15px;
font-size:85%"> Don't have an account? <a asp-action="Index"
asp-controller="UserRegistration">Sign Up Here</a> </div> <div style="font-size: 85%;"> Forgot your password? <a asp-action="ForgotPassword">Reset Password Here</a>
</div> </div>
  1. Add a new model called ResetPasswordEmailModel to the Models folder:
        public class ResetPasswordEmailModel 
        { 
          public string DisplayName { get; set; } 
          public string Email { get; set; } 
          public string ActionUrl { get; set; } 
        }
  1. Update AccountController, and then add a new method called ForgotPassword:
        [HttpGet] 
        public async Task<IActionResult> ForgotPassword() 
        { 
          return await Task.Run(() => 
          { 
            return View(); 
          }); 
        }
  1. Add a new model called ResetPasswordModel to the Models folder:
        public class ResetPasswordModel 
        { 
          public string Token { get; set; } 
          public string UserName { get; set; } 
          public string Password { get; set; } 
          public string ConfirmPassword { get; set; } 
        } 
  1. Add a new view called ForgotPassword to the Views/Account folder:
        @model TicTacToe.Models.ResetPasswordModel 
        @{ 
          ViewData["Title"] = "GameInvitationConfirmation"; 
          Layout = "~/Views/Shared/_Layout.cshtml"; 
        } 
        <div class="form-gap"></div> 
        <div class="container"> 
          <div class="row"> 
            <div class="col-md-4 col-md-offset-4"> 
              <div class="panel panel-default"> 
                <div class="panel-body"> 
                  <div class="text-center"> 
                    <h3><i class="fa fa-lock fa-4x"></i></h3> 
                    <h2 class="text-center">Forgot Password?</h2> 
                    <p>You can reset your password here.</p> 
                    <div class="panel-body"> 
                      <form id="register-form" role="form"
autocomplete="off" class="form"
method="post" asp-controller="Account"
asp-action="SendResetPassword"> <div class="form-group"> <div class="input-group"> <span class="input-group-addon"><i
class="glyphicon glyphicon-envelope
color-blue"></i></span> <input id="email" name="UserName"
placeholder="email address"
class="form-control" type="email"> </div> </div> <div class="form-group"> <input name="recover-submit"
class="btn btn-lg btn-primary btn-block"
value="Reset Password" type="submit"> </div> <input type="hidden" class="hide"
name="token" id="token" value=""> </form> </div> </div> </div> </div> </div> </div> </div>
  1. Update the UserService class and the user service interface, and then add a new method called GetResetPasswordCode:
        public async Task<string> GetResetPasswordCode(UserModel 
user) { return await _userManager.
GeneratePasswordResetTokenAsync(user); }
  1. Add a new view to the View/EmailTemplates folder called ResetPasswordEmail:
        @model TicTacToe.Models.ResetPasswordEmailModel 
        @{ 
          ViewData["Title"] = "View"; 
          Layout = "_LayoutEmail"; 
        } 
        <h1>Welcome @Model.DisplayName</h1> 
        You have requested a password reset, please click <a 
href="@Model.ActionUrl">here</a> to continue.
  1. Update AccountController, and then add a new method called SendResetPassword:
[HttpPost] 
public async Task<IActionResult> SendResetPassword(string UserName) 
{ 
  var user = await _userService.GetUserByEmail(UserName); 
  var urlAction = new UrlActionContext 
  { 
    Action = "ResetPassword", Controller = "Account", 
    Values = new { email = UserName, code = await 
_userService.GetResetPasswordCode(user) }, Protocol = Request.Scheme, Host = Request.Host.ToString() }; var resetPasswordEmailModel = new ResetPasswordEmailModel { DisplayName = $"{user.FirstName} {user.LastName}", Email =
UserName, ActionUrl = Url.Action(urlAction) }; var emailRenderService = HttpContext.RequestServices.
GetService<IEmailTemplateRenderService>(); var emailService = HttpContext.RequestServices.
GetService<IEmailService>(); var message = await emailRenderService.RenderTemplate(
"EmailTemplates/ResetPasswordEmail",
resetPasswordEmailModel,Request.Host.ToString()); try { emailService.SendEmail(UserName,"Tic-Tac-Toe Reset Password",
message).Wait(); } catch { } return View("ConfirmResetPasswordRequest",
resetPasswordEmailModel); }
  1. Add a new view called ConfirmResetPasswordRequest to the Views/Account folder:
        @model TicTacToe.Models.ResetPasswordEmailModel 
        @{ 
          ViewData["Title"] = "ConfirmResetPasswordRequest"; 
          Layout = "~/Views/Shared/_Layout.cshtml"; 
        } 
        @section Desktop{<h2>@Localizer["DesktopTitle"]</h2>} 
        @section Mobile {<h2>@Localizer["MobileTitle"]</h2>} 
        <h1>@Localizer["You have requested to reset your password,
an email has been sent to {0}, please click on the provided
link to continue.", Model.Email]</h1>
  1. Update AccountController, and then add a new method called ResetPassword:
public async Task<IActionResult> ResetPassword(string email, string code) 
{ 
  var user = await _userService.GetUserByEmail(email); 
  ViewBag.Code = code; 
  return View(new ResetPasswordModel { Token = code, UserName = email }); 
}
  1. Add a new view to the Views/Account folder called SendResetPassword:
        @model TicTacToe.Models.ResetPasswordEmailModel 
        @{ 
          ViewData["Title"] = "SendResetPassword"; 
          Layout = "~/Views/Shared/_Layout.cshtml"; 
        } 
        @section Desktop{<h2>@Localizer["DesktopTitle"]</h2>} 
        @section Mobile {<h2>@Localizer["MobileTitle"]</h2>} 
        <h1>@Localizer["You have requested a password reset, an 
email has been sent to {0}, please click on the link to
continue.", Model.Email]</h1>
  1. Add a new view called ResetPassword to the Views/Account folder:
        @model TicTacToe.Models.ResetPasswordModel 
        @{ 
          ViewData["Title"] = "ResetPassword"; 
          Layout = "~/Views/Shared/_Layout.cshtml"; 
        } 
        <div class="container"> 
          <div id="loginbox" style="margin-top:50px;"
class="mainbox
col-md-6 col-md-offset-3 col-sm-8 col-sm-offset-2"> <div class="panel panel-info"> <div class="panel-heading"> <div class="panel-title">Reset your Password</div> </div> <div style="padding-top:30px" class="panel-body"> <div class="text-center"> <form asp-controller="Account"
asp-action="ResetPassword" method="post"> <input type="hidden" asp-for="Token" /> <div asp-validation-summary="All"></div> <div style="margin-bottom: 25px" class="input-
group"> <span class="input-group-addon"><i
class="glyphicon glyphicon-envelope
color-blue"></i></span> <input id="email" asp-for="UserName"
placeholder="email address"
class="form-control" type="email"> </div> <div style="margin-bottom: 25px" class="input-
group"> <span class="input-group-addon"><i
class="glyphicon glyphicon-lock
color-blue"></i></span> <input id="password" asp-for="Password"
placeholder="Password"
class="form-control" type="password"> </div> <div style="margin-bottom: 25px" class="input-
group"> <span class="input-group-addon"><i
class="glyphicon glyphicon-lock
color-blue"></i></span> <input id="confirmpassword"
asp-for="ConfirmPassword"
placeholder="Confirm your Password"
class="form-control" type="password"> </div> <div style="margin-bottom: 25px" class="input-
group"> <input name="submit"
class="btn btn-lg btn-primary btn-block"
value="Reset Password" type="submit"> </div> </form> </div> </div> </div> </div> </div>
  1. Update the UserService class and the user service interface, and then add a new method called ResetPassword:
public async Task<IdentityResult> ResetPassword(string userName, string password, string token) 
{   
  _logger.LogTrace($"Reset user password {userName}");    
  try 
  { 
    var user = await _userManager.FindByNameAsync(userName); 
    var result = await _userManager.ResetPasswordAsync(user, token, 
password); return result; } catch (Exception ex) { _logger.LogError($"Cannot reset user password {userName} -
{ex}"); throw ex; } }
  1. Update AccountController, and then add a new method called ResetPassword:
[HttpPost] 
public async Task<IActionResult> ResetPassword(ResetPasswordModel reset) 
{ 
  if (ModelState.IsValid) 
  { 
    var result = await _userService.ResetPassword(reset.UserName,
reset.Password, reset.Token); if (result.Succeeded) return RedirectToAction("Login"); else ModelState.AddModelError("", "Cannot reset your password"); } return View(); }
  1. Start the application and go to the login page. Once there, click on the Reset Password Here link:

  1. Enter an existing user email on the Forgot Password? page; this will send an email to the user:

  1. Open the Password Reset email and click on the link provided:

  1. On the Password Reset page, enter a new password for the user and click on Reset Password. You should be automatically redirected to the Login page, so sign in with the new password:

You will be excited to learn that we have now gone through all our authentication processes, and with the skills acquired, you are now able to provide reasonable authentication to any application that you may have your hands on. Now that a user is able to be authenticated, in other words, we know who our user is, we will not stop there.

Getting into the application does not necessarily mean that you are allowed to do anything that an application offers. We now need to know whether a user is authorized to do this or that action. And that's what we will look at in the next section.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.35.194