在Django保存函数中重置密码



我目前正在使用django rest密码重置URL来满足我的密码重置需求,我把它归因于一个URL:

url("^password-reset/", include("django_rest_passwordreset.urls", namespace="password_reset")),

但是,我想使用归属于用户模型的电子邮件在模型的保存方法中调用该端点。有什么办法能做到这一点吗?

你不能调用端点在一个保存方法'中,但你可以使用信号来实现这一点。

send_password_reset_token为接收函数,在新用户创建时触发,自动向新注册用户的邮箱发送重置密码链接。

from datetime import timedelta
from django.urls import reverse
from django.conf import settings
from django.utils import timezone
from django.dispatch import receiver
from django.core.mail import send_mail
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.utils.translation import ugettext_lazy as _
from rest_framework import exceptions
from django_rest_passwordreset.models import ResetPasswordToken, clear_expired, get_password_reset_token_expiry_time, 
get_password_reset_lookup_field
from django_rest_passwordreset.signals import reset_password_token_created
@receiver(post_save, sender=User)
def send_password_reset_token(sender, instance, created, *args, **kwargs):

if created:
email = instance.email
# before we continue, delete all existing expired tokens
password_reset_token_validation_time = get_password_reset_token_expiry_time()
# datetime.now minus expiry hours
now_minus_expiry_time = timezone.now() - timedelta(hours=password_reset_token_validation_time)
# delete all tokens where created_at < now - 24 hours
clear_expired(now_minus_expiry_time)
# find a user by email address (case insensitive search)
users = User.objects.filter(**{'{}__iexact'.format(get_password_reset_lookup_field()): email})
active_user_found = False
# iterate overall users and check if there is any user that is active
# also check whether the password can be changed (is useable), as there could be users that are not allowed
# to change their password (e.g., LDAP user)
for user in users:
if user.eligible_for_reset():
active_user_found = True
# No active user found, raise a validation error
# but not if DJANGO_REST_PASSWORDRESET_NO_INFORMATION_LEAKAGE == True
if not active_user_found and not getattr(settings, 'DJANGO_REST_PASSWORDRESET_NO_INFORMATION_LEAKAGE', False):
raise exceptions.ValidationError({
'email': [_(
"There is no active user associated with this e-mail address or the password can not be changed")],
})
# last but not least: iterate over all users that are active and can change their password
# and create a Reset Password Token and send a signal with the created token
for user in users:
if user.eligible_for_reset():
# define the token as none for now
token = None
# check if the user already has a token
if user.password_reset_tokens.all().count() > 0:
# yes, already has a token, re-use this token
token = user.password_reset_tokens.all()[0]
else:
# no token exists, generate a new token
token = ResetPasswordToken.objects.create(user=user)
# send an e-mail to the user
context = {
'current_user': token.user,
'username': token.user.username,
'email': token.user.email,
'reset_password_url': "{}?token={}".format(reverse('password_reset:reset-password-request'), token.key)
}
send_mail(
'Subject here',
f'Your password_reset link is {context["reset_password_url"]}',
'from@example.com',
['to@example.com'],
fail_silently=False,
)

ResetPasswordRequestToken生成
Django邮件文档

你可以利用信号发送电子邮件:

考虑Django应用profiles(你需要找到并替换所有出现的profiles与你的应用程序名称)。

创建新文件profiles/signals.py:

from django.dispatch import receiver
from django_rest_passwordreset.signals import reset_password_token_created
from django.urls import reverse
@receiver(reset_password_token_created)
def send_token_email(sender, instance, reset_password_token, *args, **kwargs):
reset_password_url = f"{instance.request.build_absolute_uri(reverse('password_reset:reset-password-confirm'))}"
message = f"Goto <a href='{reset_password_url}'>{reset_password_url}</a> and enter new password and token({reset_password_token.key})"
# send an e-mail to the user
from django.core.mail import send_mail
send_mail('Password reset',message,'noreply@somehost.com', [reset_password_token.user.email])

updateprofiles/app.pyaddreadymethod:

# ...
class ProfilesConfig(AppConfig):
# ...
def ready(self):
import profiles.signals

我明白你想在从admin添加用户后向用户发送电子邮件。

您可以通过在管理中添加save_model函数来做到这一点。您也可以通过PasswordResetForm发送密码重置邮件。

完整的代码可以是这样的:

from django.contrib import admin
from django.contrib.auth.forms import PasswordResetForm

class UserAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
super().save_model(request, obj, form, change)
form = PasswordResetForm(data={"email": obj.email})
# calling save will send the email
form.save()

admin.site.register(User, UserAdmin)

PasswordResetForm文档:https://docs.djangoproject.com/en/3.2/topics/auth/default/#django.contrib.auth.forms.PasswordResetForm

你所需要做的就是发送一封带有令牌的电子邮件给他们,并要求他们提供令牌。

如果你在你的模型中使用一个保存方法,这个方法将被调用,每次有一个保存的更改,在该模型中的一个条目,可能不是你想要的。

最新更新