Конфигурация одноразового использования DataProtectorTokenProvider

Я пытаюсь сгенерировать токен для сброса пароля и отправить его пользователю по электронной почте с помощью 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

Помогите, пожалуйста! Большое спасибо!

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
231
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Есть два способа решить эту проблему: -

Следуя методу 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();
    }

Другие вопросы по теме