User authentication after password reset in Django

I am using the standard Django view, password_reset_confirm (), for user password reset. After the user executes the reset password in the letter, he enters a new password, and then looks at its redirection to the root of the site:

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

After being redirected by a Django user, he is not authenticated. I do not want him to enter the password again, instead I want to verify its authenticity after he set the new password.

To implement this feature, I created a delegate view. It wraps the standard and processes its output. Since standard browsing redirects the user only if the reset password succeeds, I check the status code of the response that it returns, and if it redirects, retrieves the user from the database again and confirms it.

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

Are there any better ways to do this?

+5
source share
2 answers

Vanilla django

Since password_reset_confirm not a class, you cannot fully configure it without resorting to intermediate type tricks. Therefore, what you are doing seems to be the most effective at the moment.

If django will pass request to SetPasswordForm (similar to how DRF passes request to serializers), you can overwrite the save() form to log in to the user there, however now it is impossible.

third party packages

You can also look at other third-party libraries that implement auth as class-based views. Of the quick Google searches, the most promising are:

+1
source

Running Django 1.11 allows you to do this using a class-based view. You need to redefine the password_reset_confirm URL to pass post_reset_login=True and success_url to 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' ), ] 
0
source

Source: https://habr.com/ru/post/1211362/


All Articles