PasswordResetConfirmView не работает в принципе? - PullRequest
0 голосов
/ 22 октября 2019

Здесь я не использую PasswordResetView, потому что я отправляю электронную почту через свою динамическую конфигурацию электронной почты, поэтому для этого я создал собственное представление, которое генерирует токен с использованием PasswordResetTokenGenerator, а также отправляет электронное письмо пользователю. ссылка для сброса пароля в моем письме выглядит следующим образом http://127.0.0.1:8000/password-reset/confirm/NQ/5as-b3502199950ff028a6ef/

Но после нажатия на эту ссылку она перенаправляет на password_reset_confirm, что хорошо, но в этом представлении {{form.as_p}} не работает. Это толькоотображение кнопки, но до использования auth-views.PasswordresetView форма работала, но теперь форма не передается в шаблон.

Как я могу решить эту проблему?

urls.py

 path('password-reset/',views.send_password_reset_email,name='password_reset'),
    path('password-reset/done/',auth_views.PasswordResetDoneView.as_view(template_name='password_reset_done.html'),name='password_reset_done'),
    path('password-reset/confirm/<uidb64>/<token>/',
         auth_views.PasswordResetConfirmView.as_view(template_name='password_reset_confirm.html',                                                 success_url=reverse_lazy('password_reset_complete'),),name='password_reset_confirm'),

views.py

def send_password_reset_email(request):
    form = CustomPasswordResetForm()
    if request.method == 'POST':
        form = CustomPasswordResetForm(request.POST)
        if form.is_valid():
            email = form.cleaned_data['email']
            user = get_user_model().objects.get(email__iexact=email)   
            site = get_current_site(request)
            mail_subject = "Password Reset on {} ".format(site.domain)
            message = render_to_string('password_reset_email.html', {
                "user": user,
                'domain': site.domain,
                'uid': urlsafe_base64_encode(force_bytes(user.pk)).decode(),
                'token': activation_token.make_token(user)
            })
            config = EmailConfiguration.objects.order_by('-date').first()
            backend = EmailBackend(host=config.email_host, port=config.email_port, username=config.email_host_user,
                                   password=config.email_host_password, use_tls=config.email_use_tls)
            email = EmailMessage(subject=mail_subject, body=message, from_email=config.email_host_user, to=[user.email],
                                 connection=backend)
            email.send()
            return redirect('password_reset_done')

    return render(request, 'password_reset.html',{'form':form})

password_reset_email.html

{% block reset_link %}
http://{{domain}}{% url 'password_reset_confirm' uidb64=uid token=token  %}
{% endblock %}

password_reset_confirm.html

 <form action="" method="post">
      {% csrf_token %}
       {{form.as_p}}
    <button type="submit" class="btn btn-info">Reset Password</button>
  </form>

tokens.py

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

class TokenGenerate(PasswordResetTokenGenerator):
    def _make_hash_value(self, user, timestamp):
        return (
            six.text_type(user.id)+six.text_type(timestamp)+six.text_type(user.is_active)
        )

activation_token=TokenGenerate()

1 Ответ

2 голосов
/ 22 октября 2019

Вы вложили в подкласс PasswordResetTokenGenerator, поэтому вам также понадобится использовать его при проверке токена. Django делает это легко, у PasswordResetConfirmView есть атрибут класса token_generator, поэтому вам нужно только создать подкласс для переопределения используемого им токен-генератора:

class CustomPasswordResetConfirmView(auth_views.PasswordResetConfirmView):
    token_generator = activation_token

Тогда в ваших шаблонах URL используйте это представлениедля пути 'password-reset/confirm/<uidb64>/<token>/'.

Также необходимо убедиться, что вы правильно закодировали uid. Вы можете убедиться, что сделали это правильно, проверив в своей оболочке django:

uid = force_text(urlsafe_base64_decode(uidb64))
User.objects.get(pk=uid)

, которая должна вернуть пользователя.

Обратите внимание, что ваш метод _make_hash_value небезопасен: он всегда собираетсягенерировать тот же хеш в течение одного дня, когда отметка времени остается действительной. Таким образом, его можно использовать повторно несколько раз, даже если пользователь изменил пароль, и любой, у кого есть доступ к электронной почте, сможет снова сбросить пароль. Вот почему исходный _make_hash_value генератора Django использует пароль, поэтому после его изменения он не может быть использован снова.

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

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