在 Django 中重置密码后对用户进行身份验证
Authenticate user after password reset in Django
我使用标准 Django 视图 password_reset_confirm() 来重置用户密码。用户按照信中的密码重置 link 后,他输入新密码,然后查看将他重定向到站点根目录:
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 重定向用户后,他未通过身份验证。我不想让他再次输入密码,相反,我想在他设置新密码后立即对他进行身份验证。
为了实现这个功能,我创建了一个委托视图。它包装标准的一个并处理它的输出。因为标准视图仅在密码重置成功时才重定向用户,所以我检查响应的状态代码 returns,如果是重定向,则再次从数据库中检索用户并对其进行身份验证。
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'
)
有没有更好的方法来做到这一点?
香草 Django
由于 password_reset_confirm
不是基于 class 的视图,您无法在不借助中间件类型技巧的情况下以任何重要方式干净地自定义它。因此,您正在做的似乎是目前最有效的方法。
如果 django 将 request
传递给 SetPasswordForm
(类似于 DRF 将 request
传递给序列化程序的方式),您可以覆盖表单的 save()
到在那里登录用户,但现在也是不可能的。
第 3 方包
您还可以查看其他第 3 方库,它们将 auth 实现为基于 class 的视图。通过快速 google 搜索,最有希望的是:
- django-password-reset. Seems to provide complete replacement for
auth.views
as class based views. You can overwrite form_valid
为了验证用户。
- django-class-based-auth-views(未完成)
从 Django 1.11 开始,您可以使用基于 class 的视图来执行此操作。您需要覆盖 password_reset_confirm url 以将 post_reset_login=True
和 success_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'
),
]
我使用标准 Django 视图 password_reset_confirm() 来重置用户密码。用户按照信中的密码重置 link 后,他输入新密码,然后查看将他重定向到站点根目录:
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 重定向用户后,他未通过身份验证。我不想让他再次输入密码,相反,我想在他设置新密码后立即对他进行身份验证。
为了实现这个功能,我创建了一个委托视图。它包装标准的一个并处理它的输出。因为标准视图仅在密码重置成功时才重定向用户,所以我检查响应的状态代码 returns,如果是重定向,则再次从数据库中检索用户并对其进行身份验证。
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'
)
有没有更好的方法来做到这一点?
香草 Django
由于 password_reset_confirm
不是基于 class 的视图,您无法在不借助中间件类型技巧的情况下以任何重要方式干净地自定义它。因此,您正在做的似乎是目前最有效的方法。
如果 django 将 request
传递给 SetPasswordForm
(类似于 DRF 将 request
传递给序列化程序的方式),您可以覆盖表单的 save()
到在那里登录用户,但现在也是不可能的。
第 3 方包
您还可以查看其他第 3 方库,它们将 auth 实现为基于 class 的视图。通过快速 google 搜索,最有希望的是:
- django-password-reset. Seems to provide complete replacement for
auth.views
as class based views. You can overwriteform_valid
为了验证用户。 - django-class-based-auth-views(未完成)
从 Django 1.11 开始,您可以使用基于 class 的视图来执行此操作。您需要覆盖 password_reset_confirm url 以将 post_reset_login=True
和 success_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'
),
]