Реализация сброса пароля с помощью djoser

Я хотел использовать djoser для функциональности сброса пароля и согласно документации:

PASSWORD_RESET_CONFIRM_URL

URL-адрес страницы сброса пароля вашего внешнего интерфейса. Он должен содержать заполнители {uid} и {token}, например #/password-reset/{uid}/{token}, Вы должны передать uid и токен для сброса конечной точки подтверждения пароля.

Я сделал следующее:

PASSWORD_RESET_CONFIRM_URL': 'reset/password/reset/confirm/{uid}/{token}',

URL

url(r'^reset/password/reset/confirm/(?P<uid>[\w-]+)/(?P<token>[\w-]+)/$', PasswordResetView.as_view(),),

Посмотреть:

class PasswordResetView(APIView):

   def get (self, request, uid, token):
       post_data = {'uid': uid, 'token': token}
       return Response(post_data)

В моей почте я получаю эту ссылку: http://127.0.0.1:8000/reset/password/reset/confirm/Mjk/538-954dccbc1b06171eff4d

Это очевидно, что я получу:

{
"uid": "Mjk",
"token": "538-954dccbc1b06171eff4d"

}

как мой вывод, но я хотел пойти в auth/password/reset/confirm когда пользователь нажимает ссылку в письме.

2 ответа

Давайте сначала опишем действия:

  1. Пользователь щелкает ссылку, чтобы сбросить пароль. Сброс пароля
  2. (Здесь вам понадобится форма для получения имени пользователя или адреса электронной почты, в зависимости от ваших настроек). Пользователь вводит имя пользователя и нажимает "Отправить".
  3. Пользователь получает электронное письмо со ссылкой для сброса пароля.
  4. По ссылке открывается браузер, содержащий форму "Создать новый пароль".
  5. Пользователь вводит новый пароль и отправляет форму
  6. Браузер перенаправляет страницу на домашнюю страницу и сообщает, что пароль был сброшен.

Затем вы можете использовать следующий метод для сброса пароля.

#template
<p>Use the form below to change your password. Your password cannot be the same as your username.</p>
<form role="form" method="post">
  {% csrf_token %}
  <input type="password" name="password1" placeholder="New Password">
  <input type="submit">
</form>

#view
from django.shortcuts import redirect, render
from djoser.conf import django_settings

def reset_user_password(request, uid, token):
    if request.POST:
        password = request.POST.get('password1')
        payload = {'uid': uid, 'token': token, 'new_password': password}

        url = '{0}://{1}{2}'.format(
            django_settings.PROTOCOL, django_settings.DOMAIN, reverse('password_reset_confirm'))

        response = requests.post(url, data=payload)
        if response.status_code == 204:
            # Give some feedback to the user. For instance:
            # https://docs.djangoproject.com/en/2.2/ref/contrib/messages/
            messages.success(request, 'Your password has been reset successfully!')
            return redirect('home')
        else:
            return Response(response.json())
    else:
        return render(request, 'templates/reset_password.html')

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

      #view
import requests
from django.contrib import messages
from django.contrib.sites.models import Site
from django.http import HttpResponseRedirect
from django.shortcuts import render
from rest_framework.decorators import (api_view, permission_classes,
                                       renderer_classes)
from rest_framework.permissions import AllowAny
from rest_framework.renderers import JSONRenderer, TemplateHTMLRenderer

@api_view(('GET', 'POST'))
@renderer_classes((TemplateHTMLRenderer, JSONRenderer))
@permission_classes([AllowAny])
def reset_user_password(request, **kwargs):
    # uses djoser to reset password
    if request.POST:
        current_site = Site.objects.get_current()
        #names of the inputs in the password reset form
        password = request.POST.get('new_password')
        password_confirmation = request.POST.get('password_confirm')
        #data to accept. the uid and token is obtained as keyword arguments in the url
        payload = {
            'uid': kwargs.get('uid'),
            'token': kwargs.get('token'),
            'new_password': password,
            're_new_password': password_confirmation
        }

        djoser_password_reset_url = 'api/v1/auth/users/reset_password_confirm/'
        protocol = 'https'
        headers = {'content-Type': 'application/json'}
        if bool(request) and not request.is_secure():
            protocol = 'http'
        url = '{0}://{1}/{2}'.format(protocol, current_site,
                                     djoser_password_reset_url)
        response = requests.post(url,
                                 data=json.dumps(payload),
                                 headers=headers)

        if response.status_code == 204:
            # Give some feedback to the user.
            messages.success(request,
                             'Your password has been reset successfully!')
            return HttpResponseRedirect('/')
        else:
            response_object = response.json()
            response_object_keys = response_object.keys()
            #catch any errors
            for key in response_object_keys:
                decoded_string = response_object.get(key)[0].replace("'", "\'")
                messages.error(request, f'{decoded_string}')
            return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
      # if the request method is a GET request, provide the template to show. in most cases, the password reset form.
      else:
        return render(request, 'account/password_reset_from_key.html')

Я добавил разрешение allowany, поскольку конечная точка API не требует аутентификации.

В URL-адресах;

      path('password/reset/<str:uid>/<str:token>/',
         reset_user_password,
         name='reset_user_password'),

Наконец, в основном файле настроек я обновил URL-адрес сброса пароля Djoser, чтобы он соответствовал URL-адресу, который я создаю выше, чтобы убедиться, что пользователь перенаправляется на нужную страницу.

      DJOSER = {
"PASSWORD_RESET_CONFIRM_URL":
    "dashboard/auth/password/reset/{uid}/{token}/",
}

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