简体   繁体   English

使用 djoser 实现密码重置

[英]password reset implementation with djoser

I wanted to use djoser for the reset password functionality and as per the documentation:我想将djoser用于重置密码功能,并按照文档:

PASSWORD_RESET_CONFIRM_URL PASSWORD_RESET_CONFIRM_URL

URL to your frontend password reset page.指向您的前端密码重置页面的 URL。 It should contain {uid} and {token} placeholders, eg #/password-reset/{uid}/{token} .它应该包含 {uid} 和 {token} 占位符,例如#/password-reset/{uid}/{token} You should pass uid and token to reset password confirmation endpoint.您应该传递 uid 和 token 来重置密码确认端点。

I have done the following:我做了以下工作:

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(),),

View :看法 :

class PasswordResetView(APIView):

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

In my mail I get this link : http://127.0.0.1:8000/reset/password/reset/confirm/Mjk/538-954dccbc1b06171eff4d在我的邮件中,我得到了这个链接: http://127.0.0.1:8000/reset/password/reset/confirm/Mjk/538-954dccbc1b06171eff4d : http://127.0.0.1:8000/reset/password/reset/confirm/Mjk/538-954dccbc1b06171eff4d : http://127.0.0.1:8000/reset/password/reset/confirm/Mjk/538-954dccbc1b06171eff4d

This is obvious that I will get :很明显,我会得到:

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

} }

as my output but I wanted to go to auth/password/reset/confirm when the user clicks the link in the mail.作为我的输出,但我想在用户单击邮件中的链接时转到auth/password/reset/confirm

Lets describe the actions first: 让我们首先描述动作:

  1. The user clicks on the link to reset the password. 用户单击链接以重置密码。 reset password 重设密码
  2. (Here you need a form to obtain a username or email address, depending on your settings) The user enters the username and clicks Submit. (根据您的设置,此处需要一个表格来获取用户名或电子邮件地址)用户输入用户名并单击Submit。
  3. The user receives an email with a link to reset the password. 用户会收到一封带有重置密码链接的电子邮件。
  4. The link opens the browser, which contains the form "Create a new password". 该链接将打开浏览器,该浏览器包含“创建新密码”形式。
  5. The user enters a new password and sends a form 用户输入新密码并发送表格
  6. The browser redirects the page to the home page and gives feedback that the password has been reset. 浏览器将页面重定向到主页,并提供密码已重置的反馈。

You can then use following method to reset the password. 然后,您可以使用以下方法重设密码。

#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')

It's always important to catch errors, handle redirects and add the default renderer classes.捕获错误、处理重定向和添加默认渲染器类总是很重要的。 In my case, I ended up using the following.就我而言,我最终使用了以下内容。

#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')

I added the allowany permission as the API endpoint does not need any authentication.我添加了 allowany 权限,因为 API 端点不需要任何身份验证。

In URLs;在网址中;

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

Finally, on the main settings file, I updated the Djoser reset password URL to match the URL I'm building above so that I ensure that the user is redirected to the page I'm intending.最后,在主设置文件中,我更新了 Djoser 重置密码 URL 以匹配我在上面构建的 URL,以便确保将用户重定向到我想要的页面。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM