Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redirect to home page after successful password change #468

Closed
Anton-Shutik opened this issue Dec 3, 2013 · 25 comments
Closed

Redirect to home page after successful password change #468

Anton-Shutik opened this issue Dec 3, 2013 · 25 comments

Comments

@Anton-Shutik
Copy link
Contributor

Try to change password at /accounts/password/change. It will offer you to change password again. How can I specify the url redirect to?

@pennersr
Copy link
Owner

pennersr commented Dec 7, 2013

The only way to do that now is override the PasswordChangeView (see the success_url property).

@DavidCain
Copy link
Contributor

@addremove, that will indeed make the password change view redirect to the home page.

However, the "endless cycle" of password change->login occurs due to PasswordChangeView redirecting to itself on success: Because changing password logs you out and because login_required is set for PasswordChangeView, it will return the URL to login, but with a redirect back to password change.

@pennersr, is there any reason why changing passwords doesn't redirect to, say, the login page? This would be the net effect of redirecting to the change password page, but without the ?next=/accounts/password/change/.

To anyone who wants the behavior described above, I fixed it like so:

# views.py
class LoginAfterPasswordChangeView(PasswordChangeView):
    @property
    def success_url(self):
        return reverse_lazy('account_login')

login_after_password_change = login_required(LoginAfterPasswordChangeView.as_view())
# urls.py
url(r'^accounts/password/change/$', views.login_after_password_change,
    name='account_change_password'),  # Place before allauth urls to override
url(r'^accounts/', include('allauth.urls')),
...

DavidCain added a commit to DavidCain/mitoc-trips that referenced this issue Oct 13, 2014
`allauth` defaults to a loop in which changing your password redirects
you to the login page, which redirects you to change your password,
which redirects you...

Change this behavior so that a successful password change just prompts
you to log in (which can redirect wherever it wants, the home page in
this case). See pennersr/django-allauth#468
for more.
@johnedstone
Copy link

One question: I've written the code as above. The new url is caught by url.conf, so I know that its using the new class that subclasses PasswordChangeView. But, the new property from success_url seems to be ignored. Is there something I am missing? That is to say nothing is being overridden.

@DavidCain
Copy link
Contributor

Hm, you're not missing anything to my knowledge. (This solution works for me)

@johnedstone
Copy link

Just to check, here is what I have

profiles/urls.py:

url(r'^password/change/$', CustomPasswordChangeView.as_view(),
    name="password_change"),

profiles/views.py:

class CustomPasswordChangeView(PasswordChangeView):

    @property
    def success_url(self):
        print 'start'
        return '/unknown/'

This should result in:

  • printing 'start', while in debug mode to the console
  • upon success, go to /unknown/

Neither of these happen. It just seems to pass through and use everything in PasswordChangeView.

Note: if I add this block to allauth/account/views.py, then it redirects to /unknown/

@DavidCain
Copy link
Contributor

Your URL pattern should likely read ^accounts/password/change/$. Also, does your URL pattern come before the include for allauth URLs? Django will take the first matching pattern, so if you've placed it after the include('allauth.urls'), your custom view won't be used.

@johnedstone
Copy link

Actually I didn't make this clear. I think I have covered all of your concerns. See below.

The main urls.conf grabs the url that I am using, '/accounts/profile/password/change/' with this entry:

url(r'^accounts/profile/', include('profile.urls', namespace='profile')),
url(r'^accounts/', include('allauth.urls')),

Then profiles.urls reads as noted above.
I have tested this by commenting out the line in profiles/urls.py and I get a 404 error.
I will check back later if you have any other ideas. Need to leave for the moment. Thanks

@johnedstone
Copy link

Okay, I've made some progress, based on your questions.
Instead of the urls.py that I described above, I tried this, and it worked. Thanks for helping me think though this. I'm not sure exactly why my first config didn't catch it, but maybe it'll come to me later.

For the main urls.py:

from profile import views
...
    url(r'accounts/password/change', views.custom_password_change),
    url(r'^accounts/', include('allauth.urls')),

And, from profiles/views.py:

class CustomPasswordChangeView(PasswordChangeView):

    @property
    def success_url(self):
        print 'start'
        return '/unknown/'

custom_password_change = login_required(CustomPasswordChangeView.as_view())

@johnedstone
Copy link

I understand now. Even though my first entry point was with my custom class, subsequently the template that was used posted this way:

method="POST" action="{% url 'account_change_password' %}"

So once this was submitted, the data was posted not to the url that pointed to my custom view, but to the allauth/account view that I was trying to override. Thanks again.

@psychok7
Copy link

Hey guys, how can i make it so that after a password change i don't get logged out? I am able to do the redirect but it always logges me out before which i do not want..

@benedwards44
Copy link

@psychok7 it looks like in Django 1.7 they updated the auth engine to log a user out when they change their own password. I got this working with django-allauth by overriding the form_valid method of the PasswordChangeView class and adding in update_session_auth_hash(request, user), as per the Django docs:
https://docs.djangoproject.com/en/1.8/topics/auth/default/#session-invalidation-on-password-change

My views.py:

# myproject/app/views.py
from django.contrib.auth import update_session_auth_hash
from django.contrib import messages
from allauth.account.views import PasswordChangeView
from allauth.account.adapter import get_adapter
from allauth.account import signals

class MyPasswordChangeView(PasswordChangeView):
    """
    Custom class to override the password change view 
    """

    success_url = "/my_account/"

    # Override form valid view to keep user logged i
    def form_valid(self, form):

        form.save()

        # Update session to keep user logged in.
        update_session_auth_hash(self.request, form.user)

        get_adapter().add_message(self.request,
                                            messages.SUCCESS,
                                            'account/messages/password_changed.txt')

        signals.password_changed.send(sender=self.request.user.__class__,
                                            request=self.request,
                                            user=self.request.user)

        return super(PasswordChangeView, self).form_valid(form)

password_change = login_required(MyPasswordChangeView.as_view())

And my urls.py:

# myproject/urls.py
url(r'^accounts/password/change/$', 'myapp.views.password_change', name='password_change'),
url(r'^accounts/', include('allauth.urls')),

@smcoll
Copy link

smcoll commented Jun 12, 2015

@benedwards44 thanks for that. it makes sense to me that a password reset would invalidate all sessions, but revalidate the current session only.

@psychok7
Copy link

@benedwards44 thanks works great

@frederikbotha
Copy link

@benedwards44 thanks

@Omnipresent
Copy link

@benedwards44 will this keep the user logged in after they change their password but just update the current users session?

@benedwards44
Copy link

@Omnipresent that's correct, the user will stay logged in.

@dmischel
Copy link

@benedwards44 that works great (django 1.11) and thanks, mate, for the snippet. Just what I needed. I presume allauth is not being actively maintained any longer, howsomever useful.

@doganmeh
Copy link

This issue seems to have started about redirecting to an url after successful change of the password and, somehow, have evolved into re-validating the session after the password change. I just checked with allauth version 0.36 and the session was valid after the password change, so there is no need for custom code.

As far as the redirect is concerned, I came to think that it is more appropriate to show the password change form in a modal, thus, the user will just exit out of, and there will be no need to redirect.

@ghost
Copy link

ghost commented Jun 13, 2019

This is still broken. I am on django-allauth 0.39.1 and django 1.11. After successful password change I am always redirected back to reset password page (/accounts/password/change/) .

I also tried to use ACCOUNT_LOGOUT_REDIRECT_URL="/" and even ACCOUNT_LOGIN_ON_PASSWORD_RESET=True but those options are completely ignored :(

@hipertracker
Copy link

hipertracker commented Jun 14, 2019

Problem solved. To fix the URL of the page after the password has been changed and the user has logged:

First, override allauth url:

url(r"^accounts/password/change/$", CustomPasswordChangeView.as_view(), name="account_password_change")

Second, change success_url attribute:

from allauth.account.views import PasswordChangeView

class CustomPasswordChangeView(PasswordChangeView):
    success_url = '/'

That's all.

@YashMarmat
Copy link

YashMarmat commented Jan 28, 2020

if you working on templates then you need to create a specific template file or html file which will redirect you to the home page. Also you need to put your template file in below location only !

templates(folder)/registration(folder)/password_reset_complete.html

add below code inside your password_reset_complete.html file. Do not forget to create a login.html file also (at the same location)

{% extends 'base.html' %}
{% block title %}Password reset complete{% endblock title %}
{% block content %}

<h1>Password reset complete !</h1>
<p>Your new password has been set. You can log in now on the
<a href=
"{% url 'login' %}">log in page</a>.</p>

{% endblock content %}

@efojs
Copy link
Contributor

efojs commented Jun 14, 2020

Can be done solely in urls.py with success_url= argument passed to as_view() function (but anyway a better place for the logic is in the views.py):

from allauth.account import views as allauth_views
from django.contrib.auth.decorators import login_required
from django.urls import reverse_lazy

urlpatterns = [
    path(
        'account/password/change/', 
        login_required(
            allauth_views.PasswordChangeView.as_view(
                success_url=reverse_lazy('some_path_name')
            )
        ), 
        name='account_change_password'
    ),
    # after custom pattern
    path('account/', include('allauth.urls')),
]

@cemonel
Copy link

cemonel commented Mar 4, 2021

url(r"^accounts/password/change/$", CustomPasswordChangeView.as_view(), name="account_password_change")

Don't forget to add login_required() decorator since the decorator is added explicitly on allauth side.

path("accounts/password/change/", CustomPasswordChangeView.as_view(), name="account_change_password"),

@pbadeer
Copy link
Sponsor

pbadeer commented Nov 12, 2022

Can be done solely in urls.py with success_url= argument passed to as_view() function (but anyway a better place for the logic is in the views.py):

from allauth.account import views as allauth_views
from django.contrib.auth.decorators import login_required
from django.urls import reverse_lazy

urlpatterns = [
    path(
        'account/password/change/', 
        login_required(
            allauth_views.PasswordChangeView.as_view(
                success_url=reverse_lazy('some_path_name')
            )
        ), 
        name='account_change_password'
    ),
    # after custom pattern
    path('account/', include('allauth.urls')),
]

Note that for most fresh installs nowadays, 'account/password/change/' should actually be 'accounts/password/change/' (account becomes plural). If this code isn't working, check what your other URLs are by finding this line in urls.py: path('account/', include('allauth.urls')), and if it says "account/" then use that but if it says "accounts/" then use that.

@stitch
Copy link

stitch commented Dec 20, 2023

Can be done solely in urls.py with success_url= argument passed to as_view() function (but anyway a better place for the logic is in the views.py):
...

This should be in the documentation, thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests