【问题标题】:password reset implementation with djoser使用 djoser 实现密码重置
【发布时间】:2019-06-16 18:50:55
【问题描述】:

我想根据文档使用djoser 来重置密码功能:

PASSWORD_RESET_CONFIRM_URL

您的前端密码重置页面的 URL。它应该包含 {uid} 和 {token} 占位符,例如#/password-reset/{uid}/{token}。你应该 传递 uid 和 token 来重置密码确认端点。

我做了以下事情:

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

网址

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

【问题讨论】:

  • 您是否将电子邮件正文作为 html 页面发送?
  • 我不确定你的意思。您希望电子邮件中的 url 为 auth/password/reset/confirm 吗?那么为什么不把它放在 PASSWORD_RESET_CONFIRM_URL 设置中呢?它应该立即起作用。
  • @Ahtisham 是的,电子邮件正文是 html 页面
  • @KamilNiski 如果我在电子邮件中发送auth/password/reset/confirm,那么我将无法获得 uid 和令牌来知道用户是谁。而auth/password/reset/confirm 是一个POST url,其字段为uidtokennew_password

标签: django django-rest-framework djoser


【解决方案1】:

让我们先描述一下动作:

  1. 用户点击链接重置密码。 reset password
  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')

【讨论】:

    【解决方案2】:

    捕捉错误、处理重定向和添加默认渲染器类始终很重要。就我而言,我最终使用了以下内容。

    #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 端点不需要任何身份验证。

    在网址中;

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

    最后,在主设置文件中,我更新了 Djoser 重置密码 URL 以匹配我在上面构建的 URL,以确保用户被重定向到我想要的页面。

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

    【讨论】:

      猜你喜欢
      • 2021-01-27
      • 2021-10-05
      • 2015-03-06
      • 1970-01-01
      • 2021-03-11
      • 1970-01-01
      • 1970-01-01
      • 2017-07-26
      • 1970-01-01
      相关资源
      最近更新 更多