【问题标题】:Authenticate user after password reset in Django在 Django 中重置密码后对用户进行身份验证
【发布时间】:2015-03-16 14:47:19
【问题描述】:

我使用标准的 Django 视图 password_reset_confirm() 来重置用户的密码。用户点击信中的密码重置链接后,输入新密码,然后查看将他重定向到站点根目录:

urls.py

url(r'^password-reset/confirm/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
        'django.contrib.auth.views.password_reset_confirm', {
        'template_name': 'website/auth/password_reset_confirm.html',
        'post_reset_redirect': '/',
    }, name='password_reset_confirm'),

Django 重定向用户后,他没有通过身份验证。我不想让他再次输入密码,而是想在他设置新密码后立即对他进行身份验证。

为了实现这个功能,我创建了一个委托视图。它包装标准一并处理其输出。因为标准视图仅在密码重置成功时才会重定向用户,所以我检查它返回的响应的状态代码,如果是重定向,则再次从数据库中检索用户并对其进行身份验证。

urls.py

url(r'^password-reset/confirm/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
        views.password_reset_confirm_delegate, {
        'template_name': 'website/auth/password_reset_confirm.html',
        'post_reset_redirect': '/',
    }, name='password_reset_confirm'),

views.py

@sensitive_post_parameters()
@never_cache
def password_reset_confirm_delegate(request, **kwargs):
    response = password_reset_confirm(request, **kwargs)
    # TODO Other way?
    if response.status_code == 302:
        try:
            uid = urlsafe_base64_decode(kwargs['uidb64'])
            user = User.objects.get(pk=uid)
        except (TypeError, ValueError, OverflowError, User.DoesNotExist):
            pass
        else:
            user = authenticate(username=user.username, passwordless=True)
            login(request, user)
    return response

backends.py

class PasswordlessAuthBackend(ModelBackend):
    """Log in to Django without providing a password.

    """
    def authenticate(self, username, passwordless=False):
        if not passwordless:
            return None
        try:
            return User.objects.get(username=username)
        except User.DoesNotExist:
            return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

settings.py

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'website.backends.PasswordlessAuthBackend'
)

有没有更好的方法来做到这一点?

【问题讨论】:

  • 谢谢你。您帮助我了解如何从 kwargs 获取用户 ID 解码。您可以从请求的 POST 参数中获取密码,这样您就不必实现不同的身份验证后端。
  • 你不能把密码从 POST 参数中提取出来吗?如果我没记错的话,那么你就不需要无密码的身份验证后端。

标签: django django-authentication


【解决方案1】:

从 Django 1.11 开始,您可以使用基于类的视图来做到这一点。您需要覆盖 password_reset_confirm url 以将 post_reset_login=Truesuccess_url 传递给 PasswordResetConfirmView

urlpatterns += [
 url(
   r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
    views.PasswordResetConfirmView.as_view(
      post_reset_login=True,
      success_url=reverse_lazy('studygroups_login_redirect')
    ),
    name='password_reset_confirm'
  ),
]

【讨论】:

  • 感谢指出reverse_lazy的存在!
  • 这应该是公认的答案。在 Django 3.1 中工作
【解决方案2】:

原版 Django

由于password_reset_confirm 不是基于类的视图,如果不借助中间件类型的技巧,您就无法以任何重要的方式干净地自定义它。因此,您正在做的似乎是目前最有效的方式。

如果 django 将 request 传递给 SetPasswordForm (类似于 DRF 将 request 传递给序列化程序的方式),您可以覆盖表单的 save() 以在那里登录用户,但现在这也是不可能。

第三方包

您还可以查看将身份验证实现为基于类的视图的其他 3rd 方库。从快速的谷歌搜索中,最有希望的是:

【讨论】:

  • 关于我们如何覆盖form_valid 函数的任何示例。?这将有很大的帮助。谢谢。
猜你喜欢
  • 1970-01-01
  • 2021-06-11
  • 1970-01-01
  • 2014-04-29
  • 2013-03-11
  • 1970-01-01
  • 2020-10-30
  • 2019-01-10
  • 1970-01-01
相关资源
最近更新 更多