public async Task <IActionResult> ForgotPassword(ForgotPasswordViewModel model) { if (ModelState.IsValid) { var user = await userManager.FindByNameAsync(model.Email); if (user == null || !(await userManager.IsEmailConfirmedAsync(user))) { // 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 http://go.microsoft.com/fwlink/?LinkID=532713 // Send an email with this link var code = await userManager.GeneratePasswordResetTokenAsync(user); var resetUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme); // best security practice is to not disclose the existence of user accounts // so we show the same message whether the password reset request is for an // actual account or not but if it is an actual account we send the email // problem I have noticed is that there is a noticable delay after clicking the button // in the case where we do send an email, as such it is pretty easy to guess from this that // the account exists. I think we need to either eliminate the apparent delay by // spawning a separate thread to send the email or by introducing a similar delay // for non existing accounts //ThreadPool. // await emailSender.SendPasswordResetEmailAsync( // not awaiting this awaitable method on purpose // so it does not delay the ui response // vs would show a warning squiggly line here if not for .Forget() //http://stackoverflow.com/questions/35175960/net-core-alternative-to-threadpool-queueuserworkitem //http://stackoverflow.com/questions/22629951/suppressing-warning-cs4014-because-this-call-is-not-awaited-execution-of-the emailSender.SendPasswordResetEmailAsync( userManager.Site, model.Email, "Reset Password", resetUrl).Forget(); return(View("ForgotPasswordConfirmation")); } // If we got this far, something failed, redisplay form return(View(model)); }
public async Task <IActionResult> ForgotPassword(ForgotPasswordViewModel model) { if (ModelState.IsValid) { var user = await userManager.FindByNameAsync(model.Email); if (user == null || (Site.RequireConfirmedEmail && !(await userManager.IsEmailConfirmedAsync(user)))) { if (user != null) { log.LogWarning(user.Email + ": user tried to use pasword recovery but no email was sent because user email is not confirmed and security settings require confirmed email"); } // 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 http://go.microsoft.com/fwlink/?LinkID=532713 // Send an email with this link var code = await userManager.GeneratePasswordResetTokenAsync(user); var resetUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id.ToString(), code = code }, protocol: HttpContext.Request.Scheme); // await emailSender.SendPasswordResetEmailAsync( // not awaiting this awaitable method on purpose // so it does not delay the ui response // vs would show a warning squiggly line here if not for .Forget() //http://stackoverflow.com/questions/35175960/net-core-alternative-to-threadpool-queueuserworkitem //http://stackoverflow.com/questions/22629951/suppressing-warning-cs4014-because-this-call-is-not-awaited-execution-of-the emailSender.SendPasswordResetEmailAsync( userManager.Site, model.Email, sr["Reset Password"], resetUrl).Forget(); //await emailSender.SendPasswordResetEmailAsync( // userManager.Site, // model.Email, // sr["Reset Password"], // resetUrl); return(View("ForgotPasswordConfirmation")); } // If we got this far, something failed, redisplay form return(View(model)); }