密码恢复 - django令牌永不过期
我已经在应用程序中设置了一个密码恢复系统,该系统效果很好,但是我面临的令牌发行的问题显然永远不会到期,至少在用户多次使用它时。
通过电子邮件发送给用户的链接即使在使用相同链接更改密码X时间后仍保持有效。
我正在使用我在Internet上使用token_generator.make_token(用户)
utils.pys.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.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.pys.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 ([email protected])")
return HttpResponseRedirect("/fr/se-connecter/")
else:
messages.error(request, f"An error occurred, please contact support ([email protected])")
return HttpResponseRedirect("/en/login/")
else:
pass
的常规方式。我的问题很简单,如果用户已经使用并成功更改了密码,我该如何从记录中删除令牌或使其无效?
预先感谢您的帮助!
I've set up a password recovery system in my application which work pretty well however I'm facing a problem with the token issued which apparently never expire, at least when it gets used multiple time by the user.
The link sent by email to the user remain valid even after changing the password x times with the same link.
I'm using the regular way I've found on internet with 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 ([email protected])")
return HttpResponseRedirect("/fr/se-connecter/")
else:
messages.error(request, f"An error occurred, please contact support ([email protected])")
return HttpResponseRedirect("/en/login/")
else:
pass
My question is simple, how can I delete the token from record or make it invalid if the user already used it AND changed his password successfully ?
Thank you in advance for your help !
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这并不能完全回答您的问题,因为我不认为可以将令牌设置为一种用途,但是您可以减少令牌在设置中有效的秒数。根据以下内容,默认值为3天。
password_reset_timeout = 259200#默认值:259200(3天,秒),
如果超时已超过以上,则会返回false
This doesn't fully answer your question as I don't think the tokens can be set as a one use only but you can reduce the number of seconds that the token is valid for in setting.py. The default is 3 days as per the below.
PASSWORD_RESET_TIMEOUT = 259200 # Default: 259200 (3 days, in seconds)
if the timeout has elapsed the above would return false