Я пытаюсь сгенерировать токен для сброса пароля и отправить его пользователю по электронной почте с помощью ASP .NET. Однако после проверки пользователь может снова щелкнуть ту же ссылку, и она все равно вернет истину. Я хочу настроить только одноразовое использование. Здесь генерируется код
var code = await identityUserManager.GeneratePasswordResetTokenAsync(user.Id); //the code is generated here
Здесь проверяется код
UserManager.VerifyUserToken(userId, "ResetPassword", code) //still return true after second click in Email
Помогите, пожалуйста! Большое спасибо!





Есть два способа решить эту проблему: -
Следуя методу 1, мы реализуем время истечения срока действия токена. Здесь пользователь все равно сможет дважды использовать код, время истечения если больше, чем требуется. Лучшим решением было бы установить немного RouteGuards, как показано в методе 2. После этого нет позволит пользователю посетить страницу сброса пароля во второй раз, без сгенерирует новый код. Итак, здесь пользователь сможет использовать код только один раз. Но это одно использование будет без истечения срока действия
Итак, чтобы получить оба преимущества, я рекомендую реализовать оба Таким образом, пользователь сможет использовать код только один раз, и это тоже до истечения срока действия.
Метод 1 - (Реализовать время истечения срока действия токена)
Создайте базу данных с 3 столбцами (TokenCode, IssuedToEmailId, ExpireTime), чтобы хранить то же самое, с EmaildId в качестве первичного ключа, чтобы пользователю нельзя было выдавать больше одного токена за один раз. И сразу после создания токена в ForgetPassword(). как показано ниже, удалите любую предыдущую строку в таблице этого пользователя и вставьте новые данные -> код токена, идентификатор электронной почты пользователя и время истечения срока действия, то есть, скажем, Datetime.Now.AddMinutes(10);
И в приведенном ниже ResetPassword() извлеките данные из таблицы, используя идентификатор электронной почты, и сравните Datetime.Now < ExpireTime, если это правда, продолжайте, иначе покажите ошибку просроченного кода.
Метод 2 - (Реализовать Route Guard)
Мой поток кода для сброса пароля заключается в том, что на странице забытого пароля я запрашиваю только адрес электронной почты, а затем нажимаю кнопку, чтобы запустить процесс генерации токена, отправки электронной почты и т. д. Итак, после успешной отправки электронной почты я делаю return Ok() и запустите сеанс в sessionStorage и перейдите на страницу сброса пароля. Теперь, оказавшись здесь, я проверяю наличие того же сеанса, если он не найден, я понимаю, что он был удален, и направляю пользователя туда, где я хочу, но если сеанс присутствует, я прошу ввести новый пароль, подтвердить новый пароль , а затем, скажем, нажатие кнопки запускает процесс сброса пароля, и на его return Ok() я удаляю этот сеанс.
Итак, в случае, если пользователь пытается снова использовать тот же токен, посетив URL-адрес сброса пароля, у него нет этого сеанса, и поэтому он перемещается туда, где я хочу. Таким образом, мне не нужно проверять токен пользователя.
Коды =>
Забудьте код пароля: -
public async Task<IHttpActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindByNameAsync(model.Email);
// If user has to activate his email to confirm his account, the use code listing below
//if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
//{
// return Ok();
//}
if (user == null)
{
return NotFound();
}
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
await UserManager.SendEmailAsync(user.Id, "Reset Password for AJWebApp", $"Please reset your password by using this => {code}");
return Ok();
}
// If we got this far, something failed, redisplay form
return BadRequest(ModelState);
}
Код сброса пароля: -
public async Task<IHttpActionResult> ResetPassword(ResetPasswordViewModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var user = await UserManager.FindByNameAsync(model.Email);
if (user == null)
{
// Don't reveal that the user does not exist
return Ok();
}
var result = await UserManager.ResetPasswordAsync(user.Id, model.Code, model.Password);
if (result.Succeeded)
{
return Ok();
}
return Ok();
}