Восстановление пароля - срок действия токена Django никогда не истекает

Я установил систему восстановления пароля в своем приложении, которая работает довольно хорошо, однако я столкнулся с проблемой, связанной с выпущенным токеном, срок действия которого, очевидно, никогда не истекает, по крайней мере, когда он используется пользователем несколько раз.

Ссылка, отправленная по электронной почте пользователю, остается действительной даже после смены пароля x раз с использованием той же ссылки.

Я использую обычный способ, который я нашел в интернете с token_generator.make_token(user)

utils.py

from django.contrib.auth.tokens import PasswordResetTokenGenerator
from six import text_type

class AppTokenGenerator(PasswordResetTokenGenerator):

    def _make_hash_value(self, user, timestamp):
        return (text_type(user.is_active), text_type(user.pk), text_type(timestamp))


token_generator = AppTokenGenerator()

api_email.py

def send_email_user_account_password_recover(request, user, language):
    try:
        uidb64 = urlsafe_base64_encode(force_bytes(user.pk))
        token = token_generator.make_token(user)

        url_base = get_url_base(request)
        email_text = emailText["user_account_password_recover"][language]

        if language == "fr":
            link_text = "Réinitialiser mon mot de passe"
            activate_url = url_base + f"/fr/recover-password-authorised/{uidb64}/{token}/"
        else:
            link_text = "Reset my password"
            activate_url = url_base + f"/en/recover-password-authorised/{uidb64}/{token}/"

        context = {"title": email_text["title"],
                   "content": email_text["text"],
                   "url_base": url_base,
                   "link": activate_url,
                   "link_text": link_text,
                   "language": language}

        html_content = render_to_string("email/email-template-extends.html", context)
        text_content = strip_tags(html_content)

        email = EmailMultiAlternatives(
            subject=email_text["title"],
            body=text_content,
            to=[user.email])

        email.attach_alternative(html_content, "text/html")
        email.send(fail_silently=False)

        logger.info(f"Email user password recover for user ({user.id_code}) sent from {EMAIL_HOST_USER} to {user.email}.")
        return True

    except:
        logger.error(f"Email user password recover for user ({user.id_code}) could not be sent.")
        return False

views.py

def AccountVerification(request, language=None, uidb64=None, verification_token=None):
    if verification_token:
        if not language:
            if request.LANGUAGE_CODE == "fr":
                return HttpResponseRedirect(f'/fr/verification/email/{uidb64}/{verification_token}/')
            else:
                return HttpResponseRedirect(f'/en/verification/email/{uidb64}/{verification_token}/')

        id = force_text(urlsafe_base64_decode(uidb64))
        user = api.charge_user_from_id(id)

        try:
            if not token_generator.check_token(user, verification_token):
                logger.error(f"{get_first_part_log(request)} Link not valid anymore.")

                if language == "fr":
                    messages.error(request, f"Le lien n'est plus valide.")
                    return HttpResponseRedirect("/fr/se-connecter/")
                else:
                    messages.error(request, f"The link is not valid anymore.")
                    return HttpResponseRedirect("/en/login/")

            if user.is_active:
                logger.info(f"{get_first_part_log(request)} User already activated, redirect to login.")

                if language == "fr":
                    return HttpResponseRedirect("/fr/se-connecter/")
                else:
                    return HttpResponseRedirect("/en/login/")

            user.is_active = True
            user.is_email_validated = True
            user.save()

            logger.info(f"{get_first_part_log(request)} Charging email verification completed page.")

            if language == "fr":
                return render(request, "fr/authentication/email-verification-completed.html", {})
            else:
                return render(request, "en/authentication/email-verification-completed.html", {})

        except:
            logger.error(f"{get_first_part_log(request)} An error occurred.")

            if language == "fr":
                messages.error(request, f"Une erreur est survenue, contactez le support (support@linkimo.fr)")
                return HttpResponseRedirect("/fr/se-connecter/")
            else:
                messages.error(request, f"An error occurred, please contact support (support@linkimo.fr)")
                return HttpResponseRedirect("/en/login/")

    else:
        pass

Мой вопрос прост, как я могу удалить токен из записи или сделать его недействительным, если пользователь уже использовал его и успешно сменил пароль?

Заранее благодарю за помощь!

Это не полностью отвечает на ваш вопрос, поскольку я не думаю, что токены могут быть установлены как одноразовые, но вы можете уменьшить количество секунд, в течение которых токен действителен в файле setting.py. По умолчанию это 3 дня, как показано ниже.

PASSWORD_RESET_TIMEOUT = 259200 # По умолчанию: 259200 (3 дня, в секундах)

token_generator.check_token(user, verification_token)

если тайм-аут истек, вышеуказанное возвращает false

Вернуться на верх