使用 DRF 时未显示 Django 密码重置表单,可从网站使用

问题描述 投票:0回答:1

我的 Django 应用程序遇到涉及密码重置功能的问题。当通过标准 Django 网站流程发送密码重置链接时,一切都会按预期进行:用户收到一封包含链接的电子邮件,单击该链接后,他们将进入一个包含重置密码表单的页面。

但是,当通过 Django Rest Framework (DRF) API(从 Flutter 应用程序触发)发送重置链接时,用户仍然会收到带有链接的电子邮件,但打开的页面不会显示密码重置表单。页面上的其余 HTML 内容可以正确呈现,但表单本身丢失。

这是 Django 中我的 CustomPasswordResetConfirmView 的相关部分:

class CustomPasswordResetConfirmView(PasswordResetConfirmView):
    form_class = SetPasswordForm
    success_url = reverse_lazy('users:password_reset_complete')
    template_name = 'users/password_reset_confirm.html'

    @method_decorator(sensitive_post_parameters('new_password1', 'new_password2'))
    @method_decorator(csrf_protect)
    def dispatch(self, *args, **kwargs):
        return super().dispatch(*args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['form'] = self.form_class(user=self.request.user)
        return context

模板users/password_reset_confirm.html如下:

        <main class="mt-5" >
            <div class="container dark-grey-text mt-5">
                <div class="content-section">
                    <form method="POST">
                        {% csrf_token %}
                        <fieldset class="form-group">
                            <legend class="border-bottom mb-4">Reset Password</legend>
                            {{ form|crispy }}
                        </fieldset>
                        <div class="form-group">
                            <button class="btn btn-outline-info" type="submit">Reset Password</button>
                        </div>
                    </form>
                </div>
            </div>
        </main>

我不确定到底要寻找什么,要么是发送给用户进行重置的链接不正确,因为从网站收到电子邮件时显示的链接如下:

Subject: [Displayname] Password Reset E-mail
Hello from [Displayname]!

You're receiving this e-mail because you or someone else has requested a password for your user account.
It can be safely ignored if you did not request a password reset. Click the link below to reset your password.

https://www.[Domain].com/password-reset-confirm/1h/bxogub-7eebb4**************deaa0e/

In case you forgot, your username is Username.

Thank you for using [Displayname]!
www.[Domain].com

从 DRF API 来看,flutter 看起来像这样:

Subject: Password reset on [Displayname]
You're receiving this email because you requested a password reset for your user account at [Displayname].

Please go to the following page and choose a new password:

https://www.[Domain].com/password-reset-confirm/NTM/bxogt6-68772***************f41836/

Your username, in case you’ve forgotten: Username

Thanks for using our site!

The [Displayname]team
django django-rest-framework django-forms
1个回答
0
投票

听起来 Django 站点(URL 中的 1h)和 DRF API (NTM) 之间的链接格式不匹配导致验证失败。

DRF 重置令牌可能与 Django 的预期格式不兼容。

最好的做法是以 Django 相同的方式生成令牌,直接在 DRF 视图中使用 PasswordResetTokenGenerator。

这样链接格式将匹配,避免当用户单击密码重置 URL 时 Django 端出现任何验证错误。

from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode

class CustomPasswordResetConfirmView(PasswordResetConfirmView):
    # Your existing code...

    def get_reset_token(self, user):
        token_generator = PasswordResetTokenGenerator()
        uidb64 = urlsafe_base64_encode(force_bytes(user.pk))
        token = token_generator.make_token(user)
        return f"{uidb64}/{token}"

    def send_reset_email(self, user):
        reset_token = self.get_reset_token(user)
        reset_link = f"https://www.[Domain].com/password-reset-confirm/{reset_token}/"
        # Send the email with the correct reset link
        # ...

    # Your existing code...

需要检查的一些关键事项:

  • 令牌生成应与 Django 的PasswordResetTokenGenerator 完全匹配。

  • 记录令牌以确保其符合预期格式。

  • 确认 urls.py 中重置的 URL 结构与 API 提供的匹配。

  • 在PasswordResetConfirmView 上记录视图参数可能会发现值不匹配。

该问题似乎源于 DRF 和 Django auth 之间的令牌格式不一致。确保每个 PasswordResetTokenGenerator 生成的令牌相同,并且 URL 模式正确排列应该可以解决该问题。

记录整个过程将有助于查明发生错误或不匹配的位置。通过一些调试,我们可以让这个密码重置流程在 API 和网站上无缝运行。

© www.soinside.com 2019 - 2024. All rights reserved.